Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 429|回复: 0

[Java基础知识]重新编写Object类中的方法

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-1 09:56:29 | 显示全部楼层 |阅读模式
    function TempSave(ElementID)
                            {
                                    CommentsPersistDiv.setAttribute("CommentContent",document.getElementById(ElementID).value);
                                    CommentsPersistDiv.save("CommentXMLStore");
                            }
                            function Restore(ElementID)
                            {
                                    CommentsPersistDiv.load("CommentXMLStore");
                                    document.getElementById(ElementID).value=CommentsPersistDiv.getAttribute("CommentContent");
                            }
                   
                      









          Object类是所有类的超类,也就是说,java中的每一个类都是由Object扩展而来的。因而每当你创建一个对象,它都将拥有Object类中的全部方法。让我们先来看看java.lang.Object的中的主要方法有哪些:

      
      
       
       
    public class Object{
    //公共构造函数
    public Object();
    //公共实例方法
    public boolean equals(Object obj);
    public native int hashCode();
    public final native Class getClass();
    public String toString();
    public final native void notify();
    public final native void notifyAll();
    public final void wait() throws InterruptedException;
    public final native void wait(long timeout) throws InterruptedException;  
    public final void wait(long timeout, int nanos) throws InterruptedException;
    //保护实例方法
    protected native Object clone();
    protected void finalize() throws Throwable; }   

         方法equals测试的是两个对象是否相等,方法clone进行对象拷贝,方法getClass返回和当前对象相关的Class对象,方法notify,notifyall,wait都是用来对给定对象进行线程同步的。

         然而Object类所提供的只是一些基本的方法,我们在编写自己的类时经常需要覆盖这些方法,一方面是加强功能,另一方面也是为了适应当前的情况。这就引出了本文的主题――

    如何编写自己的equals方法  
         首先要明确一个问题,Object类中的equals方法是怎样判断两个对象是否相等的呢?让我们来看看它的源代码:

    public boolean equals(Object obj)  
    {
          return (this == obj);
    }
       
    不难看出,它仅仅判断了两个对象的引用是否相等,这在很多情况下并没有太大的实际意义。比如,我们需要一个比较两个字符串是否相等,在String类中就覆盖了这个方法。标准的java类库中有超过150个equals方法的实现。然而java语言规范要求equals方法具有以下性质:

    自反性:对于任何非空引用x, x.equals(x)返回true。
       
    对称性:对于任何非空引用x和y, 当且仅当y.equals(x)返回true时,x.equals(y)返回true。
       
    传递性:对于任何引用x,y和z,如果x.equals(y)返回true并且y.equals(z)也返回true,那么x.equals(z)应该返回true。

    一致性:如果x和y引用的对象没有改变,那么x.equals(y)的重复调用应该返回同一结果。  
    对于任何非空引用x, x.equals(null)应该返回false。  

    这5条规则显示良好的逻辑性,想要写好自己的equals方法,必须满足它们。那么如何才能做到这些规则呢?


      
       
       

         
       

         
       
      
       
         
    假设当前equals方法传进来的参数名为otherObject,

    测试this是否与otherObject相等。  
    测试otherObject是否为null,如果是,一定要返回false。  
    测试this通otherObject是否同属于一个类。这是为了满足规则2。  
    把otherObject强制转换为另一个变量(这里称为other):Classname other = (Classname) otherObject。然后比较所有的字段。使用 == 比较基本类型字段,使用equals方法比较对象字段。如果所有的字段都匹配返回true,否则返回false。  
    下面举一个简单的例子:

    class TestEqual{
         int number;
         String s;
        public boolean equals(Object otherObject){
         //首先看看这两个对象引用是否相等
         if (this == otherObject)  
              return true;
         //这是为了满足规则5
         if(otherObject == null)
             return false;
         //如果两个对象所属类型不同,它们不可能相等
         if(getClass() != otherObject.getClass())  
             return false;
         TestEqual other = (TestEqual)otherObject;
         //比较所有字段
             return s.equals(otherObject.s) && number == otherObject.number;
         }
    }  

         这个例子虽然很简单,但却清晰地反映出了以上所说的要点。

         还有一个需要注意的地方是,在子类中,首先要调用超类的equals方法,如果这项测试无法通过,那么两个对象不可能相等。也就是:

    if(!super.equals(otherObject)) return false;
       

    到这里相信大家已经对编写自己的equals方法有了一定的认识,只要在平时写程序的时候多注意一下,写好它并不难。

    再来看看本文的第二大主题:

       

    如何编写自己的clone方法  
          类似equals方法,我们先来讨论一下Object的clone方法效果是怎样的。不过在此之前,有个问题要提一下,所有使用clone方法的类,不论是继承Object.clone()还是覆盖它,都必须实现一个名为cloneable的接口。如果你打开java类库查一下,会发现这个接口里什么也没有,它仅仅是表明某个类具有被clone的能力。

    用一个例子来研究一下Object.clone()的复制效果:

    public class TestClone1 implements Cloneable{
          int count;
          TestClone1 next;

          public TestClone1(int count) {
               this.count=count;
               if(count>0)
                    next=new TestClone1(count-1);
          }

          void add(){
               count++;
               if(next!=null)
               next.count++;
          }

          public String toString(){
               String s=String.valueOf(count)+" ";
               if(next!=null)
               s+=next.toString();
               return s;
          }

          public Object clone(){
               Object o=null;
         //如果没有实现cloneable,将会抛出CloneNotSupported异常
               try{
               o=super.clone();
               }
               catch(CloneNotSupportedException e){
               System.err.println("cannot clone");
               }
               return o;
          }

          public static void main(String[] args){
               TestClone1 t=new TestClone1(1);
               System.out.println("t="+t);
               TestClone1 t1=(TestClone1)t.clone();
               System.out.println("t1="+t1);
               t.add();
               System.out.println("after added
    t t="+t+"
    t1="+t1)
         }
    }

       
    在这个例子中创建t相当于两个相连的TestClone1实例,而在调用了t的add方法之后,意想不到的结果出现了:  
    t=1 0  
    t1=1 0  
    after added
    t t=2 1  
    t1=1 1  
    t1也发生了改变,这点也许有些出乎你的意料。实际上Object.clone()进行的复制有着"bitwise"原则,也就是逐位复制。对于一个对象中定义的对象,它只是简单的复制这个对象的引用。这也就是常说的浅层拷贝(shallow copy),明白了这一点,想要执行深层拷贝(deep copy)也就不难了。

    只需要在TestClone1 t1=(TestClone1)t.clone();后面加上t1.next=(TestClone1)t.next.clone();就能得到:

    t=1 0  
    t1=1 0  
    after added
    t t=2 1  
    t1=1 0  
    这个正确的结果。

         接下来要介绍的是,如何控制clone能力。从前面可以知道,clone()是protected的,你必须覆盖并实现cloneable接口并处理必要的异常才能使用它。这样,你在设计自己的类时,有以下几种风格来控制clone能力:

         不理会clone(),也就是在你的类中不涉及任何有关clone()的内容,如果有人想实现clone功能,必须写一个子类并完成刚才所说的要求。这适合于Object.clone()可以胜任复制你的类中全部字段的情况。  
         支持clone()。你在你的类中实现cloneable接口并且覆盖clone方法以及捕获相应的异常。  
         有条件的支持clone()。这种情况有些特殊,也就是你的类中保存着一些可能不能被复制的对象的引用(这里是指它们没有实现cloneable)。这时候你只是在clone()中复制所有这些对象,如果遇到异常,抛出所有这些异常给使用你的类的人。举个例子,假设你在写一个类似于ArrayList的类,你不知道别人会在把什么样的对象保存在你的ArrayList里,所以你也不知道他们是否能够被复制。  
         不实现cloneable接口但覆盖clone方法为protected。这样你虽然让你的类不能被复制,但却提供了正确的clone方法,这样如果有人想复制你的类,写一个子类实现cloneable接口就行了。  
         不实现cloneable接口并覆盖clone方法直接抛出异常来防止你的类被复制。不过这并不是根本的解决方法,只能对付那些直接调用你的clone方法或是在子类中调用super.clone()的人。  
         使用final修饰你的类来防止你的类被复制。如果你的超类中有覆盖clone方法的,再重新覆盖clone方法并直接抛出异常。这也是最彻底的办法。  
         希望通过本文的介绍,能够使大家对Object类有个大概的了解,编写好自己的equals和clone方法,以适应不同的需要。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-2 15:10 , Processed in 0.388179 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表