Object 浅读

一、源码

 /* 通过JNI对本地方法进行注册,映射本地函数与Java方法之间的关系*/
private static native void registerNatives();   

 /* 在对象初始化时自动调用 registerNatives() */    
static {     
    registerNatives();     
}     

/* 返回此 Object 的运行时类*/   
public final native Class<?> getClass()

/*返回该对象的哈希码值。默认情况下,该方法根据对象的地址来计算哈希码值*/
public native int hashCode()

/*比较两个对象是否同一 */  
public boolean equals(Object obj)

/*本地CLONE方法,用于对象的复制 */  
protected native Object clone() throws CloneNotSupportedException

/*返回该对象的字符串表示*/    
public String toString()

/*唤醒在此对象监视器上等待的单个线程*/ 
public final native void notify()

/*唤醒在此对象监视器上等待的所有线程。*/ 
public final native void notifyAll()

/*在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待*/
public final native void wait(long timeout) throws InterruptedException

public final void wait(long timeout, int nanos) throws InterruptedException

public final void wait() throws InterruptedException

 /*当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法*/    
protected void finalize() throws Throwable {}

二、hashCode()

hashCode 的通用约定:

  • 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的散列值,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
  • 如果根据 equals() 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的散列值。
  • 如果根据 equals(t) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不要求一定生成不同的散列值。但是,程序员应该意识到,为不相等的对象生成不同散列值可以提高哈希表的性能。
  • 当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的散列值可。

三、equals()

  • 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
  • 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
  • equals() 具有对称性、自反性、传递性。
  • 对任何为 null 的对象调用 x.equals(null) 结果都为 false

四、clone()

clone() 有 protected、native 关键字修饰,那么我们需要重写 Object 的 clone() 实现对象的克隆。

1、浅拷贝

浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个也会随之变化。

public class Student implements Cloneable {
	// 姓名
	private String name;
	// 年龄
	private int age;
	// 分数
	private Score Score;

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public Student(String name, int age, Score score) {
		super();
		this.name = name;
		this.age = age;
		Score = score;
	}

	public Score getScore() {
		return Score;
	}

	public void setScore(Score score) {
		Score = score;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ",mathematics score=" + Score.getMathematics()
				+ ",chinese score=" + Score.getChinese() + "]";
	}

	// 重写Object的clone方法
	public Student clone() throws CloneNotSupportedException {
		return (Student) super.clone();
	}

}

class Score {
	private int mathematics;
	private int chinese;

	public Score(int mathematics, int chinese) {
		super();
		this.mathematics = mathematics;
		this.chinese = chinese;
	}

	public int getMathematics() {
		return mathematics;
	}

	public void setMathematics(int mathematics) {
		this.mathematics = mathematics;
	}

	public int getChinese() {
		return chinese;
	}

	public void setChinese(int chinese) {
		this.chinese = chinese;
	}

}

@Test
public static void testShallowClone() throws CloneNotSupportedException {
	Score score = new Score(99, 90);
	Student orgin = new Student("二牛", 22, score);
	Student clone = orgin.clone();
	System.out.println("orgin:" + orgin.toString());
	System.out.println("clone:" + clone.toString());
	orgin.setName("激动");
	orgin.setAge(1);
	score.setMathematics(100);
	score.setChinese(80);
	System.out.println("orgin:" + orgin.toString());
	System.out.println("clone:" + clone.toString());		
}

clone() 对于基本数据类型、String类型(值传递)为深拷贝,对象、数组等引用类型为浅拷贝。除了重写 clone() 方法进行浅拷贝,还可以通过拷贝构造方法实现浅拷贝

2、深拷贝

深拷贝是将对象和值都复制过来,两个对象修改其中任意的值另一个值不会改变。

public class Student implements Cloneable {
	// 姓名
	private String name;
	// 年龄
	private int age;
	// 分数
	private Score Score;

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public Student(String name, int age, Score score) {
		super();
		this.name = name;
		this.age = age;
		Score = score;
	}

	public Score getScore() {
		return Score;
	}

	public void setScore(Score score) {
		Score = score;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ",mathematics score=" + Score.getMathematics()
				+ ",chinese score=" + Score.getChinese() + "]";
	}

	// 重写Object的clone方法
	public Student clone() throws CloneNotSupportedException {
        // 拷贝 Student 对象
		Student stu = (Student) super.clone();
		// 拷贝 Student 对象 的score属性
		stu.score = stu.getScore().clone();
		return stu;
	}

}

class Score implements Cloneable {
	private int mathematics;
	private int chinese;

	public Score(int mathematics, int chinese) {
		super();
		this.mathematics = mathematics;
		this.chinese = chinese;
	}

	public int getMathematics() {
		return mathematics;
	}

	public void setMathematics(int mathematics) {
		this.mathematics = mathematics;
	}

	public int getChinese() {
		return chinese;
	}

	public void setChinese(int chinese) {
		this.chinese = chinese;
	}

    // 重写Object类的clone方法
	public ScoreD clone() throws CloneNotSupportedException {
		return (ScoreD) super.clone();
	}

}

@Test
public static void testShallowClone() throws CloneNotSupportedException {
	Score score = new Score(99, 90);
	Student orgin = new Student("二牛", 22, score);
	Student clone = orgin.clone();
	System.out.println("orgin:" + orgin.toString());
	System.out.println("clone:" + clone.toString());
	orgin.setName("激动");
	orgin.setAge(1);
	score.setMathematics(100);
	score.setChinese(80);
	System.out.println("orgin:" + orgin.toString());
	System.out.println("clone:" + clone.toString());		
}

除了重写clone方法来实现深拷贝,还可以通过对象序列化实现深拷贝:将对象序列化为字节序列后,默认会将该对象的整个对象进行序列化,再通过反序列即可实现深拷贝。

cloneable 是一个标记接口,在实现这个接口的情况下,重写Object中的clone(),然后通过类调用 clone() 才能克隆成功。否则会抛出CloneNotSupportedException。另外,若某个属性被 transient 关键字修饰,那么该属性无法被拷贝。

3、clone() 的替代方案

使用 clone() 来拷贝一个对象即复杂又有风险,它会抛出异常,并且需要强制类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。

参考:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值