java面试之Clone方法相等性判断

来源:互联网 发布:广告宣传软件 编辑:程序博客网 时间:2024/06/05 18:23

1、Clone方法

1.1、不使用clone方法

Employee tobby = newEmployee(“CMTobby”,5000);

Employee cindyelf = tobby;

这样的操作只是浅复制,tobby和cindyelf指向内存中同一个Employee类型对象,tobby.setSalary改变salary值之后,cindyelf.getSalary获取的就是salary改变之后的值。

1.2、使用clone方法

注意:

  • 调用clone方法的对象类必须实现(implements)clonable接口,否则的话就会抛出CloneNotSupportedException,同时为了能是其他类能调用这个类的clone方法,最好将clone方法改为public

这里调用的clone相当于调用的是父类Object的方法,父类方法是protected,很显然不能这样调用。

这里因为MyObject重写了方法,虽然还是protected,但是test1与MyObject在同一个包里面,所以可以调用。

  • Object类中就有clone方法(protected),但是Object又没有实现clonable接口,所以Object不能直接调用clone方法
  • 执行clone方法时首先会判断是否实现clonable接口,否则抛出错误

如果自定义类使用super.clone()方法调用object默认的clone方法,这样只是得到的一个浅复制,即基本类型直接复制一个值到复制类中,复制类中对基本类型数据改变不会影响被复制类中基本类型的值;而对于引用类型,只会复制一个引用,指向的还是被复制类中的引用对象,在复制类中对引用的改变会改变被复制类中引用变量的内容。

如果自定义类自己定义深复制,则需要新建一个引用对象,将被复制类中的引用变量的内容全部复制过来。

2、相等性判断

2.1、==

在java中利用“==”比较变量时,系统使用变量在栈中所存的值进行比较,所以:

  • 对于基本变量,就是比较变量的内容值
  • 对于引用类型变量,则比较的是所指向的对象的地址
  • 对于java.net.URL类,联网状态下直接比较url地址字符串;如果联网状态下则比较对应的IP地址

2.2、equals

equals只能应用于引用变量String除外,String比较的值内容),Object类中equals方法的定义如下:

boolean  equals(Object   o){

           return   this==o;

}

所以使用系统默认的equals方法时,还是比较的地址值,而不是对象内容值。

为了能比较对象内容的值,则必须在自定义类中对equals进行重写,同时最好也要将hashcode也进行重写(需要注意hashcode的特性——每次new一个object,这个objecthashcode是永远不同的,这样的话可能会影响equals的比较,关于hashcode具体的介绍见:http://fhuan123.iteye.com/blog/1452275)。

重写的一般步骤:

           CloneObject obj = new CloneObject();

           obj.clone(); // Compile ok

           publicboolean equals(Object o){      

          //重写equals方法,后面最好重写hashCode方法

           if(this == o)   //这样效率高  

                returntrue;

           if(o ==null)        

            returnfalse;

           if( !(oinstanceof CloneObject))

            returnfalse;

           

           final CloneObject co = (CloneObject)o;

       // 变量具体比较操作

3、instanceof、getclass()判断类对象

publicclass InstanceofGetclassDiffextends parent{

    publicstaticvoid main(String[] args)  

    {   

       InstanceofGetclassDiffa = newInstanceofGetclassDiff();

       parentb = newparent();

       System.out.println(ainstanceof parent); //输出true

       System.out.println(binstanceof InstanceofGetclassDiff); //输出false

       System.out.println(a.getClass() == b.getClass());//输出false

    }

}

class parent{}

可以看出instanceof可以判断继承关系,即“子类实例 instanceof 父类名称”这个模式,而getClass无法判断继承关系,只是简单的判断是否是一类。推广到Equals方法中的应用,当子类中自定义Equals时,则最好用getClass方法,反之如果所有子类都继承父类的Equals方法,则用instanceof。

4、String对象

4.1、Java内存分析

  • 栈(Stack) :存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中)。
  • 堆(heap):存放所有new出来的对象,在运行期创建
  • 常量池(constant pool):在堆中分配出来的一块存储区域,存放储显式的String常量和基本类型常量(float、int等)。另外,可以存储不经常改变的东西(public static final),在编译期就创建。常量池中的数据可以共享。
  • 静态存储:存放静态成员(static定义的)。

4.2、String str =“abc”

       String a = "abc";

       String b = "abc";

分析:第一行代码执行后在常量池(constantpool)中创建了一个值为abc的String对象,第二行执行时,因为常量池中存在"abc"所以就不再创建新的String对象了。

4.3、String str =new String(“abc”)

        String c = new String("xyz");

        String d = new String("xyz");

分析:第一行中Class被加载时,"xyz"被作为常量读入,在常量池(constantpool)里创建了一个共享的值为"xyz"的String对象;然后当调用到new String("xyz")的时候,会在堆(heap)里创建这个new  String("xyz")对象;第二行执行时,由于常量池(constant pool)中存在"xyz"所以不再创建"xyz",然后创建新的new String("xyz")。

4.4、String str =“123” + new String(“abc”)

这行复制语句表示的是先在常量池(constantpool)里创建了一个共享的值为"xyz"的String对象(编译期确定);new String(“abc”),不能在编译期完成,需要在堆中创建对象,通过“+”操作生成一个新的字符串(在常量池中的值是“123abc”?),同时返回一个String类型变量引用。

        String s0=”kvill”;  

        String s1=new String(”kvill”);  

        String s2=”kv” + new String(“ill”);  

        System.out.println( s0==s1 );  //false

        System.out.println( s0==s2 );  //false

       System.out.println( s1==s2 );  //false

  • String.intern()应用

         返回的是String变量值内容在常量池中值的引用。

        String s1 = "Monday";

        String s2 = new String("Monday");

        s2 = s2.intern();

       System.out.println("s1 == s2");//true

0 0
原创粉丝点击