Object类的定义
public class Object
类Object是类层次结构的根类。每个类都使用Object作为超类。所有对象(包括数组)都实现这个类的方法。
Java把现实中的任何事物都当做一个对象(Object),Java是面向对象的,就是Object Orentied简称OO。此处的Object在Java中被定义为一个顶级父类,它是任何类父类,我们可以显示的继承它,也可以隐式继承,如以下实例:
public class Dog extends Object { }
与public classDog { },完全等价。
Object类有11个成员方法,分别是
clone():Object 、equals(Object):boolean、finalize():void、getClass() 、hashCode():int、
notify():void、notifyAll():void、toString():String、wait():void、wait(long):void、wait(long,int):void
Object类的方法:
1、publicboolean equals(Object obj)
看equals之前需要先看下==, 因为 == 是判断相等,equals也是判断相等,只是“==”主要用于判断基本数据类型的相等性,当然也可以直接判断两个对象。而equals主要判断对象内容。
首先 == 判断基本数据类型时,比较的是两个的值是否相等,当 == 比较的是两个引用对象是,判断的是两者的首地址是否一致(相当于判断是否是同一个引用)。
Object类中的equals()方法如下:
public boolean equals(Object obj) {
return (this == obj);
}
即Object类中的equals()方法等价于==。
只有当继承Object的类覆写(override)了equals()方法之后,继承类实现了用equals()方法比较两个对象的内容是否相等,才可以说equals()方法与==的不同。
equals()方法需要具有如下特点:
自反性(reflexive):任何非空引用x,x.equals(x)返回为true。
对称性(symmetric):任何非空引用x和y,x.equals(y)返回true当且仅当y.equals(x)返回true。
传递性(transitive):任何非空引用x和y,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)返回true。
一致性(consistent):两个非空引用x和y,x.equals(y)的多次调用应该保持一致的结果,(前提条件是在多次比较之间没有修改x和y用于比较的相关信息)。
约定:对于任何非空引用x,x.equals(null)应该返回为false。
并且覆写equals()方法时,应该同时覆写hashCode()方法,反之亦然。
2、public int hashCode()
返回该对象的哈希码值(hashcode value,一个整型值)。支持此方法是为了提高哈希表(例如java.util.Hashtable提供的哈希表)的性能。如果两个对象被equals()方法判断为相等,那么它们就应该拥有同样的hash code。
当你覆写(override)了equals()方法之后,必须也覆写hashCode()方法,反之亦然。
Object类的hashCode()方法为不同的对象返回不同的值,Object类的hashCode值表示的是对象的地址。
hashCode的一般性契约(需要满足的条件)如下:
1、在Java应用的一次执行过程中,如果对象用于equals比较的信息没有被修改,那么同一个对象多次调用hashCode()方法应该返回同一个整型值。应用的多次执行中,这个值不需要保持一致,即每次执行都是保持着各自不同的值。
2、如果equals()判断两个对象相等,那么它们的hashCode()方法应该返回同样的值。
3、并没有强制要求如果equals()判断两个对象不相等,那么它们的hashCode()方法就应该返回不同的值。即,两个对象用equals()方法比较返回false,它们的hashCode可以相同也可以不同。但是,应该意识到,为两个不相等的对象产生两个不同的hashCode可以改善哈希表的性能。
3、public String toString()
返回该对象的字符串表示。通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。
Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:getClass().getName() + ‘@’ +Integer.toHexString(hashCode())。
当打印引用,如调用System.out.println()时,会自动调用对象的toString()方法,打印出引用所指的对象的toString()方法的返回值,因为每个类都直接或间接地继承自Object,因此每个类都有toString()方法。
4、protected Object clone() throws Clone NotSupportedException
创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。
这样做的目的是,对于任何对象 x,表达式:x.clone() != x为true,表达式:x.clone().getClass() == x.getClass()也为true,但这些并非必须要满足的要求。一般情况下: x.clone().equals(x)为true,但这并非必须要满足的要求。
首先,使用这个方法的类必须实现java.lang.Cloneable接口,否则会抛出CloneNotSupportedException异常。Cloneable接口中不包含任何方法,所以实现它时只要在类声明中加上implements语句即可。
第二个比较特殊的地方在于这个方法是protected修饰的,覆写clone()方法的时候需要写成public,才能让类外部的代码调用。
按照惯例,返回的对象应该通过调用super.clone获得。如果一个类及其所有的超类(Object除外)都遵守此约定,则 x.clone().getClass() == x.getClass()。
按照惯例,此方法返回的对象应该独立于该对象(正被复制的对象)。要获得此独立性,在super.clone返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被复制对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改 super.clone 返回的对象中的字段。
也就是clone的浅拷贝和深拷贝问题,在具体使用的时候需要特别注意:
浅拷贝:如果一个对象内部还有一个引用类型的基本变量,那么在拷贝该对象的时候,只是在通过clone方法新产生的新对象中拷贝一个该基本类型的引用。换句话说,也就是新对象和原对象他们内部都含有一个指向同一对象的引用。
深拷贝:拷贝对象的时候,如果对象内部含有一个引用类型的变量,那么就会再将该引用类型的变量指向的对象复制一份,然后引用该新对象。
5、public final Class<?>
getClass()返回此Object的运行时类。返回的Class对象是由所表示类的static synchronized 方法锁定的对象。
实际结果类型是Class<?extends |X|>,其中|X|表示清除表达式中的静态类型,该表达式调用getClass。例如,以下代码片段中不需要强制转换:
Number n = 0;
Class<? extends Number> c = n.getClass();
6.protected void finalize() throws Throwable
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。子类重写finalize方法,以配置系统资源或执行其他清除。
finalize 的常规协定是:当 Java 虚拟机已确定尚未终止的任何线程无法再通过任何方法访问此对象时,将调用此方法,除非由于准备终止的其他某个对象或类的终结操作执行了某个操作。finalize 方法可以采取任何操作,其中包括再次使此对象对其他线程可用;不过,finalize 的主要目的是在不可撤消地丢弃对象之前执行清除操作。例如,表示输入/输出连接的对象的 finalize 方法可执行显式 I/O 事务,以便在永久丢弃对象之前中断连接。
Object 类的 finalize 方法执行非特殊性操作;它仅执行一些常规返回。Object 的子类可以重写此定义。
Java 编程语言不保证哪个线程将调用某个给定对象的 finalize 方法。但可以保证在调用 finalize 时,调用 finalize 的线程将不会持有任何用户可见的同步锁定。如果 finalize 方法抛出未捕获的异常,那么该异常将被忽略,并且该对象的终结操作将终止。
在启用某个对象的finalize 方法后,将不会执行进一步操作,直到 Java 虚拟机再次确定尚未终止的任何线程无法再通过任何方法访问此对象,其中包括由准备终止的其他对象或类执行的可能操作,在执行该操作时,对象可能被丢弃。
对于任何给定对象,Java虚拟机最多只调用一次 finalize 方法。finalize 方法抛出的任何异常都会导致此对象的终结操作停止,但可以通过其他方法忽略它。
7、wait()与notify/notifyAll方法
首先必须要注意的是wait()与notify/notifyAll 方法必须在同步代码块中使用。
当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。当执行notify/notifyAll方法时,会唤醒一个处于等待该对象锁的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁,即任然会执行notify/notifyAll 后面的代码,只要在对象锁锁住的代码区域内。
这里需要注意,notify/notifyAll()执行后,并不立即释放锁,而是要等到执行完临界区中代码后,再释放。故在实际编程中,我们应该尽量在线程调用notify/notifyAll()后,立即退出临界区。即不要在notify/notifyAll()后面再写一些耗时的代码。此外wait()方法唤醒的线程也不是立马就能获得锁,进入运行状态,wait方法只是唤醒它进入等待队列。