Java的equals和==问题

来源:互联网 发布:面试软件开发岗位 编辑:程序博客网 时间:2024/05/16 12:11
Java中equals和==的区别,是十分经典的问题。本人有次面试时,就被问了这个问题。在此深入研究下。
第一原则:
equals和==都是比较变量(varivable)才可以比较。类、方法、接口等非变量是不能比较的。 
以下代码,编译器是不能通过的。
eg1:class A{     void fun(){     }}class B{     void fun(){     }}interface C{}interface D{}public class test2 {     public static void main(String[] args){           A a = new A();           B b = new B();           System. out.println(A.equals( B));           System. out.println(C.equals( D));     }}

第二原则:
基础数据类型是可以直接用==比较的。

在第一原则的情况下,Java的变量分为基本数据类型和引用型,两者比较是不同的。
首先熟悉下Java的变量存储机制。
1、基本数据类型(包括数值型,字符型和布尔型)在创建时,在栈上给其划分一块内存,将数值直接存储在栈(stack)上。
  
2、引用数据类型在被创建时,首先要在栈上给其引用(句柄)分配一块内存,而对象的具体信息都存储在堆内存上,然后由栈上面的引用指向堆中对象的地址。
          在eg1中,A a = new A(),简单的一句话,其实执行了如下的步骤:
               step1:在stack区分配了一块区域,存放a;
               step2:在heap区新建A的一个对象;
               step3:将A对象在堆内存中的地址,赋值给栈中的a,通过句柄a可以找到堆中对象的具体信息。
当我们使用==比较时,比较的是在stack内容中存储的内容,所以基础类型是可以直接用==比较的,那么引用型的呢?
第三原则:
     引用型变量的比较,要具体情况具体分析。
     结合具体情况是指结合什么东西的具体情况呢,当然是指JDK文档中的不同对象的equals方法了。
     情况一:
eg2:     class A{      void fun(){     }   }   public class test2 {      public static void main(String[] args){           A a1 = new A();           A a2 = new A();           System. out.println(a1.equals(a2));     }   }   

打印结果是false,这是怎么回事?当我们新建A对象时,继承的是java.lang.Object,并且没有重写equals方法。而Object类中的equals方法是用来比较“地址”的,所以等于false。
     
     情况二:
eg3:     public class test2 {      public static void main(String[] args){           String str = new String( "helloworld");           String str2 = new String( "helloworld");           System. out.println(str.equals(str2));     }   }

打印结果是true,这是怎么回事?在JDK中String的equals方法已经被重写,比较就是内容,所以等于true。

情况三:
eg4:     public class test2 {      public static void main(String[] args){           StringBuffer str = new StringBuffer( "helloworld");           StringBuffer str2 = new StringBuffer( "helloworld");           System. out.println(str.equals(str2));     }   }

 打印结果是false,这是因为StringBuffer并没有重写equals方法,还是比较的地址。
 读到这里,大家也许明白了,equals千万不能死记硬背,要根据JDK的文档来查看相应对象的比较方法才行。而我们自己定义的类,如果想用equals的比较的话,就需要重写了。
 eg5:     class A{      private String age;      public String getAge() {            return age;     }      public void setAge(String age) {            this. age = age;     }      public boolean equals(A a) {            return this. age.equals(a. age);     }          }     public class test2 {          public static void main(String[] args){           A a1 = new A();           a1.setAge( "12");           A a2 = new A();           a2.setAge( "12");           System. out.println(a1.equals(a2));          }     }  

打印结果是true! 
PS:还有一种很特殊的情况,既可以使用equals又可以使用==,这就涉及到Java的装箱拆箱了(详见笔者的另一篇文章:点击打开链接)。
     分析:
     在C语言中,数组的定义方法有两种:
          char  a[] = "leirenbaobao"          
          char  *p =  "leirenbaobao"
     第一种是用数组定义,第二种是用指针指向字符串常量区的一个字符串,而字符串常量区有个特性:当我定义了char  *p =  "leirenbaobao"时,再定义个char *q = "leirenbaobao",这时候字符常量区不再新建另一个"leirenbaobao",而是将两个指针同时指向一个第一个"leirenbaobao",想必这样也是为了程序执行的效率吧。

     而在java中,也是这尿性,java的字符串常量区,有时也被称为字符串常量池。
eg6:     public class test2 {      public static void main(String[] args){           String str = "leirenbaobao";           String str2 = "leirenbaobao";           System. out.println(str.equals(str2));           System. out.println(str==str2);     }   }

结果返回两个true。

     Ctrl+Z presents!


0 0
原创粉丝点击