Object类学习总结
在Java中有这样一个类,它是所有类的祖先,任何类都是其子孙类,它就是java.lang.Object,如果一个类没有显式地指明其父类,那么它的父类就是Object。
Object类位于java.lang包中,java.lang包包含着Java最基础和核心的类,在编译时会自动导入。Object类没有定义属性,一共有13个方法,具体的类定义结构如下图:
在java中除了基本型别(数字、字符、布尔值,primitive type)不是对象之外,其它的均为对象(class type)。那么,这个Object到底给我们留下了什么“遗产”呢?下面将从最基本的讲起:
1.equals方法
. public boolean equals(Object obj
所有的类均可以按照自己的需要对equals方法进行覆盖,顾名思义,这个方法可用来比较两个对象是否“相等”,至于什么才叫“相等”,各个类可以根据自己的情况与需要自行定义。例如String,就是要求两个对象所代表的字符串值相等,而对于一个雇员类(Employee),则可能是要求姓名、年龄、工资等一样才算是“相等”。尽管不同的类有不同的规则,但是有一条规则却是公用的,它就是:如果两个对象是“一样”(identical)的,那么它们必然是“相等”(equals)的。那么什么才叫“一样”?如果a==b,我们就说a和b是“一样的”,即a和b指向(refer to)同一个对象。Object类中的equals方法实施的就是这一条比较原则,对任意非空的指引值a和b,当且仅当a和b指向同一个对象时才返回true。
打开JDK5.0的帮助文档,我们会看到equals方法必须满足一系列性质:
A.自反性,即对任意一个非空的指引值x,x.equals(x)永远返回true;
B.对称性,对任意非空的指引值x和y,当且仅当x.equals(y)返回true时y.equals(x)返回true;
C.传递性,当x.equals(y)返回true并且y.equals(z)返回true时,x.equals(z)也返回true;
D.一致性,对任何非空的指引值x和y,只要x和y所指向(refer to)的对象没有发生变化,那么x.equals(y)的结果也不会变化;
E.对任意非空的指引值x,x.equals(null)应该返回false。
如何才能打造一个“完美”的equals方法呢,下面时JavaCore给出的建议:
第一步:把显式参数声明为otherObject(这个看个人喜好,不一定非得叫otherObject,至于什么叫显式参数什么叫隐式参数我就不赘术了)
第二步:检查待比较得两个值是否指向同一个对象(identical),就是用==进行比较,这是一个比较偷懒的步骤,如果那两个东东都一样了,就不用再比了。
第三步:测试otherObject是否为null,如果是则返回false
第四步:用getClass()方法或者instance of关键字对otherObject进行测试,主要是看待比较的两个reference是否指向同一个class type或者otherObject是否指向隐式参数所属的类或子类
第五步:通过第四步的测试后,就可以进行强制类型转换了,把otherObject强制转换成与隐式参数相同的类型
第六步:根据自己的业务逻辑和需要定义什么时候才是equal,如对所有的域进行比较,如果全部相同就返回true,否则返回false
2. hashCode()方法返回一个整形数值,表示该对象的哈希码值
public int hashCode()
每个类都可以复写Object类中的hashCode方法,Object类中的hashCode方法就是简地将对象在内存中的地址转换成int返回。这样,如果一个类没有复写hashCode方法,那么它的hashCode方法就是简单地返回对象在内存中的地址。
在JDK中,对hashCode也定义了一系列约束,其中有一条就是如果两个对象是“equal”的,那么它们的hashCode方法返回的整数值必须相同,但是如果两个对象是“unequal”,那么hashCode方法的返回值不一定必须不同。正因为这个约束,我们如果复写了equals()方法,一般也要复写hashCode方法。
3.public String toString()
toString方法是一个从字面上就容易理解的方法,它的功能是得到一个能够代表该对象的一个字符串,Object类中的toString方法就是得到这样的一个字符串:this.getClass().getName() + ‘@’ + Integer.toHexString(hashCode()),各个类可以根据自己的实际情况对其进行改写,通常的格式是类名[field1=value1,field2=value2……fieldn=valuen]。Core上面说这个方法对于写日志非常有用,暂时还没试过:)。
4wait(…) / notify() / notifyAll()()
一说到wait(…) / notify() | notifyAll()几个方法,首先想到的是线程。确实,这几个方法主要用于java多线程之间的协作。先具体看下这几个方法的主要含义:
wait():调用此方法所在的当前线程等待,直到在其他线程上调用此方法的主调(某一对象)的notify()/notifyAll()方法。
wait(long timeout)/wait(long timeout, int nanos):调用此方法所在的当前线程等待,直到在其他线程上调用此方法的主调(某一对象)的notisfy()/notisfyAll()方法,或超过指定的超时时间量。
notify()/notifyAll():唤醒在此对象监视器上等待的单个线程/所有线程。
wait(…) / notify() | notifyAll()一般情况下都是配套使用。下面来看一个简单的例:
“`
ackage com.qqyumidi;
public class ThreadTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
synchronized (r) {
try {
System.out.println("main thread 等待t线程执行完");
r.wait();
System.out.println("被notity唤醒,得以继续执行");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("main thread 本想等待,但被意外打断了");
}
System.out.println("线程t执行相加结果" + r.getTotal());
}
}
}
class MyRunnable implements Runnable {
private int total;
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (this) {
System.out.println("Thread name is:" + Thread.currentThread().getName());
for (int i = 0; i < 10; i++) {
total += i;
}
notify();
System.out.println("执行notif后同步代码块中依然可以继续执行直至完毕");
}
System.out.println("执行notif后且同步代码块外的代码执行时机取决于线程调度");
}
public int getTotal() {
return total;
}
}
“`既然是作用于多线程中,为什么却是Object这个基类所具有的方法?原因在于理论上任何对象都可以视为线程同步中的监听器,且wait(…)/notify()|notifyAll()方法只能在同步代码块中才能使用。
从上述例子的输出结果中可以得出如下结论:
1、wait(…)方法调用后当前线程将立即阻塞,且适当其所持有的同步代码块中的锁,直到被唤醒或超时或打断后且重新获取到锁后才能继续执行;
2、notify()/notifyAll()方法调用后,其所在线程不会立即释放所持有的锁,直到其所在同步代码块中的代码执行完毕,此时释放锁,因此,如果其同步代码块后还有代码,其执行则依赖于JVM的线程调度。
* r protected void finalize();*
finalize方法主要与Java垃圾回收机制有关。首先我们看一下finalized方法在Object中的具体定义:
1 protected void finalize() throws Throwable { }
我们发现Object类中finalize方法被定义成一个空方法,为什么要如此定义呢?finalize方法的调用时机是怎么样的呢?
首先,Object中定义finalize方法表明Java中每一个对象都将具有finalize这种行为,其具体调用时机在:JVM准备对此对形象所占用的内存空间进行垃圾回收前,将被调用。由此可以看出,此方法并不是由我们主动去调用的(虽然可以主动去调用,此时与其他自定义方法无异)。
JVM垃圾回收机制是Java中重点的一块内容,在以后的博文中也将会详细总结。