Object类的clone/equals/toString常用方法详解

Object类是所有Java类的祖先。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。

一、clone方法
这几天在看接口的这一章,在Comparable接口中看到了一个不知道怎么解释的问题:Object类是所有类的父类,为什么实现Comparable接口的子类一定要重写Object类用protected修饰的的clone方法而不能直接使用?

看了好几遍都不知道是什么原因,写程序试一下发现确实是这样。若没有重新,在主类中调用实现Comparable接口的类的对象的clone()时编译报错:The method clone() from the type Object is not visible。网上查才发现原来是我对protected的认识存在误区——搞混了作用范围。

接下来就来分析一下clone方法重写的必要性以及如何进行深拷贝:

以下面程序段为例:(为了方便数据域都设置为public)
class House implements Cloneable {
	public java.util.Date date;
	public String id;
	public int area;
	public House(String id,int area) {
		this.date=new java.util.Date();
		this.id=id;
		this.area=area;
	}
	public Object clone() throws CloneNotSupportedException{
		super.clone();
		String id;
		int area;
		java.util.Date date=new java.util.Date();
		id=this.id;
		area=this.area;
		date.setTime(this.date.getTime());
		return new House(id,area);
	}
}

public class Test {    
	public static void main(String[] args) throws CloneNotSupportedException { 
		House h1=new House("1",5);
		House h2=(House)h1.clone();
		System.out.println(h1==h2);
		System.out.println(h1.id==h2.id);//true 因为限定字符串
		System.out.println(h1.date==h2.date);//false 深复制了,指向不同Date对象
		System.out.println(h1.date.toString());
		System.out.println(h2.date.toString());//结果和上一句相等
	 }
}

上面代码值得一提的是,这一个 深拷贝的例子。其中System.out.println(h1.id==h2.id);的结果是true ,因为限定字符串的原因(String的内容相同则指向同一个对象);而System.out.println(h1.date==h2.date);的结果是false,是因为已经进行深复制了,此时两个date是指向不同Date对象。

回到正题,这里必须强调 protected的保护规则
修饰符为protected的方法在同包中与public的作用范围相同(Object类的包是java.lang)。
但在不同包中,子类只能在自己的作用范围内访问自己继承的父类protected域(如任何类都可直接访问Object的clone方法),但无法访问到别的类继承的protected域。例如,在主类Test中无法访问House类继承的clone方法(即不可在Test的main方法中使用h1.clone(),但Test的对象可以使用t.clone()))。
因此我们要继承后修改可见性为public,使在Test类的作用范围内可访问House对象的clone方法。
注:clone方法被覆盖之后相当于是子类自己定义的方法,同一包的其他类可见 。

二、equals方法
先上一段源代码:
public boolean equals(Object obj) {  
    return this == obj;  
}  
这是equals方法在Object类中的实现。可以看到,该方法相当于==,即判断调用equals的对象和形参obj所引用的对象是否是同一对象。要注意:即便是内容完全相等的两块不同的内存对象,也返回false。
然而看了书上的例子:
java.util.Date date1=new java.util.Date();
java.util.Date date2=(java.util.Date)date1.clone();
System.out.println(date1==date2);//false
System.out.println(date1.equals(date2));//true
结果是一个false一个true,理由是二者是内容相同的不同对象。但这和上面的实现方法相矛盾。
疑惑时突然发现是因为我忽略掉了一点——Date类中 已重写了equals方法!此外,java中大部分类也都重写过equals方法。
这样就可以解释,为什么自己写的类若没有覆盖equals方法就直接使用得到的结果是和==一样,但使用java中已有的类的equals方法就是判断二者的内容是否相等了。
因此,如果希望在不同内存但相同内容的两个对象使用equals方法时返回true,需要重写父类的equals方法。

三、toString方法
以前一直没有注意这个方法,是在涉及到接口和抽象类时才好好理解了一下。
首先,使用System.out.print(obj)可以打印出对象obj的字符串表示,运行时JVM会自动调用toString方法,即相当于System.out.print(obj.toString())。
而默认的toString方法获得的字符串由类名+标记符@+此对象哈希码的无符号十六进制表示组成。所以,在自定义的类中一般也会重写该方法,以获得我们真正需要的信息。

四、其他方法
除了上面四个常用方法,Object类中还有其他方法,由于目前不经常使用,在此仅列出而不赘述:
finalize() :当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。 
getClass():返回一个对象的运行时类。 
hashCode() :返回该对象的哈希码值。 
notify() :唤醒在此对象监视器上等待的单个线程。 
notifyAll() :唤醒在此对象监视器上等待的所有线程。  
wait() :导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。 
wait(long timeout) :导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。 
wait(long timeout, int nanos) :导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值