Java:Object类详解
来源:互联网 发布:c excel重复数据删除 编辑:程序博客网 时间:2024/06/05 08:10
首先,我们都知道Java所有的类都继承自超类【Object】,也就是说所有的类都是Object的子类,这是一个隐式的,我们并不需要特别的指出。
我们定义一个类A。
class A { public A() { super(); }}
代码并不难懂,就是写了类A的构造函数。但是这里需要注意的是super关键词,调用的是父类的构造函数,我们可以跟进一下,就会跳到Object类去了。也就是说类A虽然没有明确的写出继承Object,但是Java还是让其继承了Object类。
Object类是有很多好处的,在本文中,我会慢慢讲述。
我们首先看看Object类主要的方法
protected Object clone()创建并返回此对象的一个副本。
boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。
protected void finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
Class
public class Main { public static void main(String[] args) { A a = new A("Aiden"); A b = a; System.out.println(a); System.out.println(b); System.out.println(a.name.hashCode()); System.out.println(b.name.hashCode()); }}class A { String name; public A(String name) { this.name = name; }}
我们看看输出结果:
test.A@2a139a55test.A@2a139a556325626163256261
可以看出对象a和对象b输出的内容是一样的。@前面表示的是对象映射的类,@后面表示的是对象的哈希地址。而name的哈希码也是相同的。
在更多的时候,我们需要深拷贝,即拷贝出两个内容相同、但引用地址不同的对象。我们就可以重写clone()方法去实现了。
下面是简单的实现。
public class Main { public static void main(String[] args) { A a = new A("Aiden"); A b = a.clone(); System.out.println(a); System.out.println(b); System.out.println(a.name.hashCode()); System.out.println(b.name.hashCode()); }}class A { String name; public A(String name) { this.name = name; } @Override protected A clone() { String name = new String(this.name); return new A(name); }}
我们来看看输出的结果:
test.A@2a139a55test.A@15db97426325626163256261
我们看看,两个对象的引用确实不同了吧。可是两个对象的内容name初始的哈希码怎么还是一样的呢?好神奇。这是因为String是常量,所有的内容存储于常量池中,每次的赋值都会去常量池中找,如果找到了就将内容匹配的地址赋值给name,如果找不到,就新建一块内存,用于存储想要赋值的内容。
2、boolean equals(Object obj)方法
这个方法是用于比较两个对象是否相同的。相同的定义包括了它们所属的类相同以及哈希码相同。我们可以跟进Object类中的equals()方法。
public boolean equals(Object obj) { return (this == obj);}
如果不重写equals()方法的话,equals就是 == 符号的作用。
A a = new A("Aiden");A b = new A("Aiden");System.out.println(a.equals(b));b = a;System.out.println(a.equals(b));
输出结果:
falsetrue
但是,我们经常看到String对象如果要比较内容的话,使用的是equals()方法,也就是说String类的实现肯定是重写了equals()方法的。我们可以看看源码:
public boolean equals(Object anObject) { if (this == anObject) { // 如果两个对象的引用相同,则返回true return true; } if (anObject instanceof String) { // 如果anObject是String对象的 String anotherString = (String)anObject; int n = value.length; // 比较每个字符串是否相同 if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false;}
源码还是很简单的,注释也写了,就不多说了。
3、protected void finalize()
该方法是用于回收”垃圾“的。当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。详情可以参考博文:点击参考
4、int hashCode()方法
该方法返回该对象的哈希码。关于哈希码的定义,官方是这么说的
hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。 hashCode 的常规协定是: 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。 以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。 实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。) 当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
官方定义给出我们对象的哈希码最好是不一致的。这样在equals()方法才能不同。
我们先看看如果给出相同哈希码的两个对象做比较时,会出现怎样的情况。我们就重写了hashCode()方法、equals()方法。
import java.util.HashSet;import java.util.Set;public class Main { public static void main(String[] args) { A a = new A("Aiden"); A b = new A("Aiden"); System.out.println(a == b); System.out.println(a.equals(b)); Set<A> set = new HashSet<>(); set.add(a); set.add(b); System.out.println(set.size()); }}class A { String name; public A(String name) { this.name = name; } @Override public int hashCode() { return 0; } @Override public boolean equals(Object object) { if (object == null) return false; if(object == this) return true; if (object instanceof A == false) return false; A b = (A)object; if(name.equals(b.name)) return true; return false; }}
我们用Set对象去检测两个对象是否哈希吗是否相同。我们看看具体的输出。
falsetrue[test.A@0]
第一行输出false,理所当然,==号是比较两个对象的引用。
第二行输出true,是因为重写了equals()方法,比较的是两个对象的name是否相同。
第三行输出却只有一个内容,也就是说HashSet在add的时候,是比较两个对象的哈希码的,如果哈希码已经存在于Set集合中,就不加入了。如果不存在Set集合中,就加入。
看来哈希码,在HashMap、HashSet、Hashtable中有广泛的应用啊。可是怎样才能实现多个对象,哈希码不相同呢?
这里给出了通用的重写hashCode()的方案:
1. 初始化一个整形变量,为此变量赋予一个非零的常数值,比如int result = 17;
2. 选取equals方法中用于比较的所有域,然后针对每个域的属性进行计算:
(1) 如果是boolean值,则计算f ? 1:0
(2) 如果是byte\char\short\int,则计算(int)f
(3) 如果是long值,则计算(int)(f ^ (f >>> 32))
(4) 如果是float值,则计算Float.floatToIntBits(f)
(5) 如果是double值,则计算Double.doubleToLongBits(f),然后返回的结果是long,再用规则(3)去处理long,得到int
(6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。 否则需要为这个域计算一个范式,比如当这个域的值为null的时候,那么hashCode 值为0
(7) 如果是数组,那么需要为每个元素当做单独的域来处理。如果你使用的是1.5及以上版本的JDK,那么没必要自己去 重新遍历一遍数组,java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上,
public static int hashCode(long a[]) { if (a == null) return 0; int result = 1; for (long element : a) { int elementHash = (int)(element ^ (element >>> 32)); result = 31 * result + elementHash; } return result; }
5、String toString()返回该对象的字符串表示。
我们可以重写这个方法,也可以重写。如果不重写,一般来说就会返回”className@hashCode“格式的字符串。也就是返回类名+”@“+哈希码。
其实我们在System.out.println(a);的时候就默认调用了a.toString()方法,所以才会输出刚刚的格式。
- Java:Object类详解
- Java:Object类详解
- Java Object类详解
- Java:Object类详解
- Java Object类详解
- Java:Object类详解
- java Object类源代码详解
- java Object类源代码详解
- Java的Object类详解
- java Object类源代码详解
- java Object类源代码详解
- java Object类源代码详解
- Java常用类--Object详解
- java的object类详解
- java Object类源代码详解 及nativ
- java中Object类 源代码详解
- java Object类 clone()方法 详解
- java中Object类 源代码详解
- Android中的Activity
- 使用Volley提交Json数据post
- Java泛型详解,通俗易懂只需5分钟
- 前端面试问题集锦
- mdf误删除碎片提取工具功能介绍
- Java:Object类详解
- 《服务的最佳实践》再实践——定时关闭程序
- ijkplayer整理笔记(四)——readThread流程图
- 真机调试解决could not find developer disk image的问题
- Spring3.2.6中事件驱动模型实现原理深入源码分析
- MySQL数据存放位置变动
- ZKW线段树之旅(1)
- 运动检测(前景检测)之(一)ViBe
- hdu5652 India and China Origins(并查集)