我们都知道:在Java中,所有的类都继承了Object这个基类,并且大家都知道,Object有几个比较通用的方法,如equals(),clone(),toString(),我们需要在使用它们的时候进行覆写,今天,我们就具体的探究下这几个方法。
void registerNatives()
这是个Native方法,在静态块中调用,其目的是将hashCode,wait,notify,notifyAll和clone方法注册到本地。
Class<?> getClass()
同样是个Native方法,获取对象的Class。
int hashCode()
Native方法,生成哈希码,其中注意三点
- 一个对象在同一个进程被多次调用,但是它的哈希码仍然应该是相同的。但是,当同一个对象在不同进程中执行,则哈希码有可能不同。JavaDoc原文如下
Whenever it is invoked on the same object more than once during an execution of a Java application, the {@code hashCode} method must consistently return the same integer, provided no information used in {@code equals} comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
- 如果两个对象通过equals()比较返回true,那么它们的哈希码应该相同。
- 如果两个对象通过equals()比较返回false,那么它们的哈希码应该不同。
boolean equals(Object obj)
这恐怕使我们最常用的方法之一了,我们在实际应用中,也经常遇到什么时候用equals(),什么时候用==的问题。一般来说,基本数据类型用==,因为这样可以直接比较它们的值,但是复合数据类型如果我们用==的话,那么实际上我们比较的就是它们的引用了,除非它们指向的是同一个对象,否则它们不可能相等,因此我们比较符合数据类型一般用equals(),并且我们应该覆写equals(),这是因为Object的equals()方法默认的也是用==进行判定:
public boolean equals(Object obj) {
return (this == obj);
}
我们再来看看我们经常用的String是如何覆写equals()方法的:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof 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;
}
在这里还有一个很有趣的问题,请看下面的例子
String s1 = "String";
String s2 = "String";
System.out.println("The result is " + s1.equals(s2));
你会发现返回值为True,这个就和我们上面讲的不一样了,按照我们上面的讲解,这时候应该返回false才对。其实是这样的,因为JVM中会维护一个字符串池,如果池中已经有包含此对象的字符串的时候,那么它就会返回池中的字符串(当然如果你new一个新的String对象的话就另当别论。)所以这个时候返回的是true。
Object clone()
Native方法,我们一般用它来复制一个对象,并且用clone()可以实现深复制(将所有需要复制的对象都复制了一遍,而不单单是用引用指向原来的对象。)示例如下:
public class Animal implements Cloneable {
private int height;
private int age;
public Animal(int height, int age){
this.height = height;
this.age = age;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Animal{" +
"height=" + height +
", age=" + age +
‘}‘;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class People implements Cloneable {
private int height;
private int age;
private Animal a;
public People(int height, int age,Animal a){
this.height = height;
this.age = age;
this.a = a;
}
@Override
public Object clone() throws CloneNotSupportedException {
People p = (People) super.clone();
p.a = (Animal) a.clone();
return p;
}
@Override
public String toString() {
return "People{" +
"height=" + height +
", age=" + age +
", a=" + a +
‘}‘;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setAnimalAge(int a) {
this.a.setAge(5);
}
}
接下来我们这样调用:
Animal a1 = new Animal(100,3);
People p1 = new People(173,24,a1);
People p2 = (People) p1.clone();
p2.setAge(26);
p2.setHeight(181);
p2.setAnimalAge(6);
System.out.println(p1.toString());
System.out.println(p2.toString());
这样我们就完成深复制了。
String toString()
最常用的方法,我们一般用它获取对象成员变量的值。Object的默认实现:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
void notify(),void notifyAll()
Native方法,多线程时应用,通知其他线程等待结束。
void wait(long),void wait(long,int),void wait()
Native方法,通知线程等待。
void finalize()
垃圾回收。当JVM判断一个对象可以被垃圾回收时,那么JVM会调用finalize()方法,但是记住,它只能调用一次(所以如果你想这个对象不被垃圾清除的话,你就要在这里面做点事情了),但是一般你不能依赖在这里做垃圾回收的工作,在《Java编程思想》中说明了有关finalize()的一个用法,那就是通过finalize()来进行对象终结对象的判断。