Class Object 是所有类的父类,但不需要显式的使用 extend 进行继承。所有对象(包括数组)都实现了这个类的方法
构造器
修饰符 | 方法名 | 描述 |
---|---|---|
public | Object() | 默认构造器 |
方法区
方法列表
修饰符 | 返回值 | 方法名 | 描述 |
---|---|---|---|
protected native | Object | clone() | 创建并返回此对象的副本 |
protected native | void | finalize() | 当垃圾收集器确定不再有对该对象的引用时,垃圾收集器在对象上调用该方法 |
public native | Class< ? > | getClass() | 返回此 Object 的运行时类 |
public native | int | hashCode() | 返回对象的哈希码值 |
public | boolean | equals(Object obj) | 指示一些其他对象是否等于此 |
public | String | toString() | 返回对象的字符串表示形式 |
public native | void | wait() | 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法 |
public | void | wait(long timeout) | 导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过 |
public | void | wait(long timeout, int nanos) | 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法,或者某些其他线程中断当前线程,或指定的时间已过 |
public native | void | notify() | 唤醒正在等待对象监视器的单个线程 |
public native | void | notifyAll() | 唤醒正在等待对象监视器的所有线程 |
clone()
protected Object clone() throws CloneNotSupportedException
创建并返回此对象的副本。
一般情况下,对于任何对象 x ,
x.clone() != x && x.clone().getClass() == x.getClass() && x.clone().equals(x),
即副本所引用的对象与正本的不为同一个, x 的运行时类与 y 相同,x 的实际内容与 y 相同。
如果调用 clone() 方法的类没有实现 Cloneable 接口,则抛出 CloneNotSupportedException 异常,
Object类本身并不实现 Cloneable 接口 ,因此在类别为 Object 的对象上调用 clone() 方法将导致运行时抛出异常。
所有数组都被认为是实现 Cloneable 接口 ,并且数组类型T[]的clone方法的返回类型是T[] ,其中T是任何引用或原始类型。
对于没有实现 Cloneable 接口的类,clone() 方法将创建类的新实例,并将其所有字段初始化为待拷贝对象相应字段的内容,就像通过赋值一样。 这些字段的内容本身不被克隆。 因此,该方法执行该对象的“浅拷贝”,而不是“深度拷贝”操作
浅拷贝
下面代码演示浅拷贝概念
public class Person implements Cloneable{
String name;
Car car;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
//省略get/set/toString方法
}
public class Car{
String brand; //品牌
int price;
//省略get/set/toString方法
}
//演示代码
public static void main(String[] args) throws CloneNotSupportedException{
//创建待拷贝实例
Car car = new Car();
car.setBrand("长城");
car.setPrice(10000);
Person person = new Person();
person.setName("赵子龙");
person.setCar(car);
//进行拷贝
Person personCopy =(Person) person.clone();
//验证拷贝方式是否为浅拷贝
personCopy.getCar().setBrand("福特");
personCopy.setName("姜子牙");
System.out.println(person.toString());
System.out.println(personCopy.toString());
//可以看到,在修改副本的 car 属性时,正本的 car 也被修改为 “福特”。
//当对象中含有可变的引用类型属性时,在复制得到的新对象对该引用类型属性内容进行修改,
//原始对象相应的属性内容也会发生变化,这就是"浅拷贝"的现象
}
序列化实现深拷贝
将对象转成二进制流,然后再把二进制流反序列成一个java对象,待拷贝类及待拷贝类的引用属性(如上文中的Car)
都需要实现 Serializable 接口,以便进行序列化。
下面代码演示序列化实现深克隆
//Person类
import java.io.*;
public class Person implements Serializable {
private static final long serialVersionUID = -1058504248325798901L;
String name;
Car car;
public Object deepClone()throws Exception{
//序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
//省略get/set/toString方法
}
//Car类
import java.io.Serializable;
public class Car implements Serializable {
private static final long serialVersionUID = 1120834063139845074L;
String brand; //品牌
int price;
//省略get/set/toString方法
}
//演示代码
public static void main(String[] args) throws CloneNotSupportedException{
//创建待拷贝实例
Car car = new Car();
car.setBrand("长城");
car.setPrice(10000);
Person person = new Person();
person.setName("赵子龙");
person.setCar(car);
//进行拷贝
Person personCopy =(Person) person.deepClone();
//验证拷贝方式是否为浅拷贝
personCopy.getCar().setBrand("福特");
personCopy.setName("姜子牙");
System.out.println(person.toString());
System.out.println(personCopy.toString());
//可以看到,在修改副本的 car 属性时,正本的 car 不再受影响。
}
clone()方法实现深拷贝
浅拷贝发生的原因是:在拷贝过程中,对于引用属性,只进行简单的值拷贝。因此,我们可以手动把引用属性拷贝一份,然后赋值给副本 演示代码如下
public class Person implements Cloneable {
String name;
Car car;
@Override
public Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.car = (Car) car.clone();
return person;
}
//省略get/set/toString方法
}
public class Car implements Cloneable{
String brand; //品牌
int price;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
//省略get/set/toString方法
}
//测试代码如下
public static void main(String[] args) throws CloneNotSupportedException{
//创建待拷贝实例
Car car = new Car();
car.setBrand("长城");
car.setPrice(10000);
Person person = new Person();
person.setName("赵子龙");
person.setCar(car);
//进行拷贝
Person personCopy =(Person) person.clone();
//验证拷贝方式是否为浅拷贝
personCopy.getCar().setBrand("福特");
personCopy.setName("姜子牙");
System.out.println(person.toString());
System.out.println(personCopy.toString());
//可以看到,在修改副本的 car 属性时,正本的 car 不再受影响。
//但因为这种方法需要将所有的引用属性手动 clone() ,如果引用类型内部仍有引用属性,
//需要进行大量编码。所以一般不用这种方法。
}
hashCode()
public int hashCode()
返回对象的 hash 值 ,设计目的:支持类似 HashMap 等的 hash 表
重写要求:
- 多次调用返回值相同 (没有要求在不同平台返回值相同)
- 两个对象调用 equals() 比较的结果如果相同,则他们调用 hashCode() 的返回值也必须相同;但 equals() 结果为不同,hashCode()可以相同,也可以不同,不同可以提高哈希表操作效率
equals()
public boolean equals(Object obj)
指示一些其他对象是否等于此。
- 自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
- 对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报true 。
- 传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true ,然后x.equals(z)应该返回true 。
- 一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,没有设置中使用的信息equals比较上的对象被修改。
- 对于任何非空的参考值x , x.equals(null)应该返回false 。
在 Object 类中,该方法比较的是两个对象的地址是否相同
如果重写该方法,需要重写 hashCode() ,保持 hashCode() 的重写要求,否则会使哈希表性能下降
wait(long timeout)
public final native void wait(long timeout) throws InterruptedException;
导致当前线程等待被唤醒,直到另一个线程调用该对象的notify()方法或notifyAll()方法,或设定的时间超时。
该方法执行之前、及被唤醒继续执行时,对象必须获得 monitor 锁 (同步锁锁住的是对象,任何时刻只能有一个线程持有),在没有获得 monitor 锁的线程中执行抛出 InterruptedException 异常。执行方法会将当前线程挂起,并将当前线程放入对象的等待队列中,然后释放掉 monitor 锁使得其他线程可以得到 monitor 锁。
该类中的另两个同名重载方法 wait() 、 wait(long timeout, int nanos) 是在该方法的基础上实现的,其等待时间分别为:无限等待、等待 timeout(毫秒) + nanos(纳秒)。所以不再单独分析。(注:等待纳秒只是单纯毫秒+1,精度没那么精确)
notify()
public final void notify()
唤醒正在等待对象 monitor 锁的单个线程。
该方法执行之前,对象必须获得 monitor 锁 ,在没有获得 monitor 锁的线程中执行抛出 InterruptedException 异常。
执行该方法之后,从对象的等待队列中移除被唤醒的线程,被唤醒的进程并不会立即执行(被唤醒继续执行时,对象必须获得 monitor 锁 ),被唤醒的进程等待得到 monitor 锁后,处于可运行状态,等待操作系统调度执行。
notifyAll()与该方法类似,唤醒所有等待进程,不再单独分析。
toString()
该方法用于返回出对象的属性对应的字符串,方便查看。
getClass()
返回对象的运行时类,运行时类的具体分析放到 Class 类中进行。