Object共有[protected]clone() equals(object obj) hashcode() toString() [protected]finalize() wait() wait(long timeout) wait(long timeout,int nanos) notify() notifyAll() getClass() 11个方法。
1 equals方法
public boolean equals(Object obj)
比较参数对象和调用对象是否相等。在Object类当中的equals方法默认比较的是地址值,在实际的开发过程当中,不满足实际的业务需求,此时需要对方法进行重写。
注意:null去调用任何方法或属性都会报NullPointerException空指针异常。
1.1 equals方法重写的步骤
- 比较参数对象和调用对象是否是同一个对象,如果是同一个对象,返回true。
- 判断参数对象和调用对象是否的是同一类。如果不是同一类,直接返回false。
- 将参数对象强转为调用对象的类型。比较参数对象和调用对象的具体的属性值,如果属性值都相同,返回的值true。说明参数对象和调用对象是一个相等的对象。在这之前先要判断引用类型的属性是否为null,否则可能会报错。
1.1.1 案例
基础类:
public class A { private B b; private String c; private int d; public B getB() { return b; } public void setB(B b) { this.b = b; } public String getC() { return c; } public void setC(String c) { this.c = c; } public int getD() { return d; } public void setD(int d) { this.d = d; } public class B { private String b; public String getB() { return b; } public void setB(String b) { this.b = b; } } }
重写equals方法:
/** * 原始的重写方法方法,兼容老版本的JDK * @param o * @return */ @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof A)) return false; A a = (A) o; if (getD() != a.getD()) return false; if (getB() != null ? !getB().equals(a.getB()) : a.getB() != null) return false; return getC() != null ? getC().equals(a.getC()) : a.getC() == null; } /** * JDK1.7之后的重写方法,使用Objects工具类 * @param o * @return */ @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof A)) return false; A a = (A) o; return getD() == a.getD() && Objects.equals(getB(), a.getB()) && Objects.equals(getC(), a.getC()); }
1.1.2 equals方法的特性
equals 方法在非空对象引用上实现相等关系:
- 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
- 对称性:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y) 才应返回 true。
- 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回
true,那么 x.equals(z) 应返回 true。 - 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上
equals 比较中所用的信息没有被修改。 - 对于任何非空引用值 x,x.equals(null) 都应返回 false。
Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y引用同一个对象时,此方法才返回 true(x == y 具有值 true)。
1.1.3 == 和 equals方法的异同点
- 相同点:都可以用来作比较。
- 不同点:
- ==:操作数可以是基本数据类型还可以是引用类型。如果是基本数据类型,比较的是具体的值的大小;如果操作数是引用类型,比较的对象的地址值。
- equals方法:操作数只能是引用(类/数组/String类(字符串)/接口/枚举)类型。默认情况(object类的equals();方法),也比较的是地址值。但是不满足实际的业务需求,需要对其进行重写。
1.1.4 String类的equals方法和object类的equals()方法
String类继承Object类后,也继承了equals方法,但String类对equals方法进行了重写,改变了equals方法的比较形式。
String(字符串)类的equals方法默认比较的也是具体的值。因此String(字符串)的内容比较应使用此方法。
1.1.4 相等的对象和相同的对象
相同的对象:地址值相同的对象,称之为相同的对象。指向堆内存当中同一个地址。equals();重写前,返回值为true时的两对象相同。
相等的对象:equals重写后,返回的值true,表明调用对象和参数对象是相等的对象。
关系:相等的对象包括相同的对象。
为了满足hashCode常规协定,要求相等对象哈希码也相等。所以需要重写hashCode()方法。相同的对象的哈希码则一定相等,因为地址值相等,而哈希码是通过地址计值算的。
2 hashCode方法
hashCode() 返回散列值,而 equals() 是用 来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。
public int hashCode()
地址值:com.ydxy.domain.Student@11e78461
@后是由十六进制的数组成。表示Student对象在堆内存的地址值,不可能重复。
哈希值:(哈希码)对地址值经过哈希算法运算得到的值int类型的值。 哈希算法:由开发者决定的。
相等的对象:
- equals方法返回true。
- hashCode对外表现一致。
问题:
- 重写equals、没有重写hashCode之后
- 相等对象:hashCode有可能相等或不相等
- 相同的对象:hashCode一定相等。
- 重写equals、重写hashCode之后
- 不相等的对象:hashCode不一定不相等。两个字符串的hashCode相同并不代表着equals比较时会相等,他们两者之间是没有必然关系
- 两对象的hashCode相等时:他们不一定相等,即equals不一定返回true。例如:“Aa””BB”的equals不等,但哈希值相等。如果哈希值相等的对象,会造成哈希冲突。String类同样默认已经对hashCode方法进行了重写.
2.1 hashCode 的常规协定
- 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals
比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 - 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode
方法都必须生成相同的整数结果。 - 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
2.2 常见hashcode值
整型:整型对象的hashcode即数据本身(hash值会强转为int型,因此如果Long型大于32位,高位会被截掉)
Boolean类型: true—1231 false—1237
Character类型:char对应的int值
3 toString方法
public String toString()
方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at
标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于: getClass().getName()+ ‘@’ + Integer.toHexString(hashCode()) 常叫做对象地址值。
Integer.toHexString(int i) -—返回参数的十六进制(基数 16)无符号整数值的字符串表示形式。即把整数转换为16进制的字符串。
形式: com.yidongxueyuan.domain.Student@3a5476a7
当对象作为print 或者是println方法的参数时候,toString方法会自动回调,即自动调用object类的toString方法
该形式是JVM能够识别的。但并不是开发人员关心的内容:所以应该对toString方法进行重写,重写后,就会默认调用重写后的toString方法。
4 getClass方法
public final Class<?> getClass()
获得了对象在运行时候的类,返回值是Class对应的字节码文件对象。
形式: class com.test.domain.Student 类的全路径(真实)名称
获得字节码文件对象的方法:
- 对象.getClass();
- 类名.class;
- Class.forName(“类的全路径名称”);
5 Finalize
protected void finalize() throws Throwable
和java当中垃圾回收机制相关的方法有关。 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
5.1 垃圾回收机制入门
java当中,JVM里面有一套自动回收垃圾的机制。不需要手动的处理垃圾。
垃圾回收过程:主要针对堆空间 标记清除法
- jvm中的垃圾回收器会不定期的对jvm当中的对象进行扫描。当在某一次扫描到某个对象没有更多的引用时候,此时垃圾回收器可能会调用finalize方法,将对象标识为垃圾,也可能直接回收(详见下部详解)。
- jvm在下一次次调用垃圾回收器,将标识为垃圾的对象进行回收。
注意:垃圾回收器(gc)只能回收内存,而且只能回收内存中由java创建对象方式(new)创建的对象所占用的那一部分内存,无法回收其他资源,比如文件操作的句柄, 数据库的连接,io流等等,这部分资源需要用户自己主动关闭!
5.2 Finalize详解:
当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,或者已经执行过一次finalize方法,则直接将其回收。
否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,下一次GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”,即finalize标记的对象有最后一次复活的机会。
程序员手动调用finalize方法并不会影响到上述内部标记的变化,因此JVM只会至多调用finalize()一次,即使该对象“复活”也是如此。并且没有外部方法能让finalize一定执行,这一点同system.gc()一样,仅仅是一个请求,最终策略由jvm说了算。
手动请求调用垃圾回收器(不一定会执行),加速垃圾回收:
System.gc(); or Runtime.getRuntime().gc();
6 clone方法
protected Object clone()
throws CloneNotSupportedException
注意:
- 对象要想被克隆,必须实现一个标志性接口:Cloneable,否则抛出异常:CloneNotSupportedException clone不支持异常。如果父类实现接口,子类便不必再实现!
- 克隆出来的新对象 和原来的对象相等但不相同。注意默认的clone方法只是浅克隆。
- 克隆方法的访问权限修饰符为protected,如果在不同包的对象中调用则需要重写为public类型;返回的是object类型,用该类接收需要强制转型。
- Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用clone方法将会导致在运行时抛出异常。
为什么clone是protected修饰的?
用protected修饰clone方法,主要是为了让子类去重写它,实现深拷贝,以防在包外其他任何地方随意调用后修改了对象的属性对原来的对象造成影响。