Java是一种面向对象编程语言(尽管不是纯粹的面向对象)。Java类层次结构的顶层是Object
类,所有的其他类都隐式的继承于它。因此,所有的类也都从Object
中继承了方法,其中最重要的几个方法如下表:
方法 | 描述 |
---|---|
protected Object clone() | 创建并返回当前对象的一份拷贝 |
protected void finalize() | 该对象不再被引用时,调用finalize() |
boolean equals(Object obj) | 判断另外一个对象是否与当前对象相等 |
int hasCode() | 返回当前对象的哈希值 |
String toString() | 返回一个表示当前对象的字符串 |
void notify() | 唤醒一个等待当前对象的锁监视器的线程。 |
void notifyAll() | 唤醒所有等待当前对象的锁监视器的线程。 |
void wait() | 进入等待状态直到其他线程调用了notify() 或notifyAll() |
1. equlas 方法
- == 用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。
- equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自
java.lang.Object
类的,所以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断。
实现equlas方法
- 检查是否为同一个对象的引用,如果是直接返回 true;
- 检查是否是同一个类型,如果不是,直接返回 false;
- 将 Object对象进行转型; 判断每个关键域是否相等。
class Person{
private String name;
private int age;
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || o.getClass() != getClass()) return false;
Person p = (Person) o;
if(name == p.name && age == p.age) return true;
return false;
}
}
2. hashCode 方法
如果两个对象通过equals()方法判等时返回true,则每个对象的hashCode()方法需要返回相同的整数值(反过来并没有限制:如果两个对象通过equals()方法返回false,则hashCode()方法可以返回相同或不同的整数值,因为有hash冲突)
HashSet 和 HashMap 等集合类使用了 hashCode() 方法来计算对象应该存储的位置,因此要将对象添加到这些集合类中,需要让对应的类实现 hashCode() 方法。
3. toString 方法
默认情况下,toString()
的结果仅仅返回以@
符分隔的全类名与对象哈希值串,然而这个结果在大多场景下并没什么用途。如下:
com.wang.Person@22927a81
4. clone 方法
4.1 Cloneable接口
clone()
方法的目的很简单——返回对象实例的拷贝,然而有一堆理由可证明其使用并不像听起来那么轻而易举。
clone()
是 Object
的 protected 方法,它不是 public,该类只有显示重写clone()方法,其他类才能调用clone()方法
@Test
public void test01() {
Person person = new Person();
try {
Object clone = person.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
class Person implements Cloneable{
private String name;
private int age;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
上面抛出了 CloneNotSupportedException
,这是因为 Person
没有实现 Cloneable
接口。
clone()
方法并不是 Cloneable
接口的方法,但Cloneable
接口只是规定,如果一个类没有实现 Cloneable
接口又调用了 clone()
方法,就会抛出 CloneNotSupportedException
。
4.2 深拷贝和浅拷贝
- 深拷贝:拷贝对象和原始对象的引用类型引用不同对象。
- 浅拷贝:拷贝对象和原始对象的引用类型引用同一个对象。
4.3 clone() 的替代方案
使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。