Object是所有对象的父类,包括数组。
public final Class<?> getClass()
该方法返回对象在运行时的类型。
这里可以同.class
方法做个对比。通常情况下,这两个方法是等价的,不同之处在于:
-
getClass
是实例方法,.class
是类方法。 -
getClass
是运行时确定的,而.class
在编译时就确定了。
比如:
public class JavaDemo {
static class Parent {
}
static class Child extends Parent {
}
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
System.out.println(parent.getClass() + " " + Parent.class);
System.out.println(child.getClass() + " " + Child.class);
Parent proxy = parent;
System.out.println(proxy.getClass());
proxy = child;
System.out.println(proxy.getClass());
}
}
输出如下:
Parent Parent
Child Child
Parent
Child
public int hashCode()
返回对象的哈希值。该方法用来辅助涉及到哈希表的类,比如HashMap。
哈希值的通用约定如下:
- 在Java应用的一次执行过程中,一个对象如果equals方法涉及到的信息没有被修改,那么多次调用hashCode返回值应该相同。多次执行同一应用不做要求。
- 如果两个对象通过equals方法比较的结果是相等的,那么hashCode返回值相同。
- 如果两个对象通过equals方法比较的结果是不相等的,那么不要求hashCode返回值一定不相同。不过hashCode返回值不同有利于提高哈希表的性能。
该方法默认将对象的内存地址转化为整数值返回。
public boolean equals(Object obj)
判断两个非null对象是否相等。该方法遵循如下规则:
对于任意非null对象x、y、z,有:
-
自反性:即
x.equals(x) == true
。 -
对称性:当且仅当
y.equals(x) == true
时,x.equals(y) == true
。 -
传递性:若
x.equals(y) == true && y.equals(z) == true
,则x.equals(z) == true
。 -
一致性:若equals方法中的信息没有被修改,则多次调用
x.equals(y)
返回值不变。 -
x.equals(null) == false
。
"equals"方法和"=="的区别在于"=="比较的是左右两边是否是同一个对象,而"equals"可自定义,其默认实现同"=="。
需要注意的是,若重写了equals方法,则也需要同时重写hashCode方法,否则可能会违背hashCode方法的第二条约定。
clone
protected Object clone() throws CloneNotSupportedException {
if (!(this instanceof Cloneable)) {
throw new CloneNotSupportedException("Class " + getClass().getName() +
" doesn't implement Cloneable");
}
return internalClone();
}
拷贝当前对象并返回。这里的拷贝依赖于对象的类型。通常情况下,对任意对象x,有:
-
x.clone() != x
。 -
x.clone().getClass() == x.getClass()
。 -
x.clone().equals(x)
。
但以上规则不是必须的。
通常来讲,返回的对象是通过调用super.clone()
获得的,并且新对象与原对象相对独立。也就是说,若类只有原始类型或者不可变类型(比如String)的成员,直接返回super.clone()
即可;若包含其他类型的对象,则需要进行“深拷贝”。
由clone方法的实现可知,要想调用clone,需要类实现Cloneable接口。数组类型实现了Cloneable接口,如果是可变对象的数组,默认实现的是浅拷贝。如下:
public class JavaDemo {
private static class Car {
}
public static void main(String[] args) {
Car car = new Car();
Car[] cars = {car};
Car[] cars2 = cars.clone();
System.out.println(cars ==+ cars2);
System.out.println(cars[0] == cars2[0]);
}
}
结果为false true
。
protected void finalize() throws Throwable
在gc回收对象时调用。子类可覆写该方法来做一些清理工作。JVM无法确保该方法在哪个线程调用。如果该方法抛出未被捕获的异常,则该异常将被忽略,并且终止对该对象的清理。
该方法至多被调用一次。一般用来回收通过特殊渠道申请的内存,比如JNI和c代码。
wait(long millis)
public final void wait(long millis) throws InterruptedException {
wait(millis, 0);
}
使当前线程进入等待状态。
要调用该方法,当前线程首先要获取该对象的锁。调用后,当前线程会首先进入该对象的等待池,然后释放该对象的锁。当前线程进入休眠状态,直到以下任意条件触发:
- 其他线程调用了该对象的notify方法,并且恰好该线程被唤醒。
- 其他线程调用了该对象的notifyAll方法。
- 其他线程调用了该线程的interrupt方法。
- 该线程的等待时间超过了millis毫秒。
触发以上任意条件后,该线程会被移出该对象的等待池,进入该对象的锁池,与其他线程竞争,等待获取该对象的锁。获取到锁之后,线程会恢复到调用wait之前的状态。
除上述条件外,线程也可能被意外唤醒。虽然这个可能性很小,但是应用应该保证线程在正确条件下被唤醒,如果条件不对,应继续等待。该方法的调用形式如下:
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
需要注意的是,调用该对象的wait方法后,该线程之后释放该对象的锁,其他对象的锁不会释放。
public final native void wait(long millis, int nanos) throws InterruptedException
同wait(long millis)。
等待的最大时间为1000000 * millis + nanos纳秒。
public final native void wait() throws InterruptedException
与wait(0)相同。
public final native void notify()
唤醒任意一个处于该对象等待池中的线程。
public final native void notifyAll()
唤醒所有处于该对象等待池中的线程。
notify和notifyAll也需要在synchronized语法块中调用。
网友评论