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

来源:互联网 发布:印度现状 知乎 编辑:程序博客网 时间:2024/05/17 18:11
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);//falseSystem.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
原创粉丝点击