JavaSE易错知识点 String 的"equals"和"=="

  对于很多初学java的同学来说,或许觉得String和int,float,这些没什么区别,可是在学习的过程中是否真的又明白呢,包括小菜在内也走了很多异想天开的弯路,总结出一些经验,所以在这里跟大家分享一下。首先,在不编译的情况的情况下看你能否答出以下三组问题的正确答案。

 

 1 public StringDemo{
 2     public static void main(String[] args){
 3         StringDemo sd = StringDemo();
 4         sd.test1();
 5         sd.test2();
 6         sd.test3();
 7     }
 8     
 9     void test1(){
10         String a = "12345";
11         String b = "12345";
12         System.out.println(a == b);
13         System.out.println(a.equals(b));
14     }
15 
16     void test2(){
17         String a = new String("12345");
18         String b = new String("12345");
19         System.out.println(a == b);
20         System.out.println(a.equals(b));
21     }
22 
23     void test3(){
24         StringBuffer a = new StringBuffer("12345");
25         StringBuffer b = new StringBuffer("12345");
26         System.out.println(a == b);
27         System.out.println(a.equals(b));
28     }
29 }

  如果说你能很轻松的答出上面的结果,那么证明你是起码知道这三者之间的区别,分清了基本数据类型和引用数据类型。

  最后的答案是:

         test1:true  true 

                         test2:  false  true

                         test3:  false  false

 

  首先,我们需要知道的是String这个类型在java中是一个特殊的类型,它既可以作为一种基本的数据类型又同时是一种引用类型,就如同int对应Integer一样,int是基本的数据类型,而Integer需要被实例化也就是new, String对应的就是String(在C#里面,为了区分,一个是大写一个是小写)。

 

  在test1中,String a="12345"和String b="12345"实际上是存放在栈空间里的,而栈空间里的数据是可以共享的,因此,当声明String a = "12345"后它会首先在栈空间内去寻找有没有“12345”这个值,没有的话,就会创建一个存放在栈内的变量值为“12345”,而再次声明b的时候,它也会去栈空间里寻找有没有“12345”,此时栈空间内已经存在这个变量了,因此,b也指向栈里面的同一块变量,所以,a和b指向同一个变量,那么a=b?很显然是相等的,这就和 int a = 1,int b =1, a = b的原理是一样的,但仔细的朋友会发现,为什么int不可以equals呢?那时因为基本数据类型是没这个方法的,在test1中,当a调用equals时,此时的String又被当作了引用类型,所以是可以调用的,所有的类继承于Obejct类,而equals正是继承下来的方法,在equals的原始定义中是比较两个对象是否相同(详参API文档),而String则重写了这个方法(详参API文档),只要对象中的字符串相同即为相同,就好比Object new了两个中国人,可这两个中国人是一个人吗?而String new了两个中国人,并且规定只要国籍是中国的,我就视作为同一个人,因此,a和b同时指向同一个对象,他们的字符串内容必然是相同的,所以a.equals(b)也是true.

 

  在test2中,a和b被作为引用类型各自new了一个实例,此时a和b各自指向的是堆空间里生成的两个实例,虽然他们包含的内容是相同的,可对于对象本身而言,他们是存放在不同的位置,所以a = b的结果是false,而对于equals而言,上一段中已经说明,由于String的equals方法是重写过的,所以只需要对象里的内容是否相同,在这里内容都是“12345”,很显然,结果就是true。.

 

  在test3中,a和b都是StringBuffer类型的,这是一个引用类型,所以当被new过后堆空间里面生成了两块对象,a和b各自指向各自new的,所以和test2一样,a = b的结果是false,那么为什么他们相同的内容equals是flase,这又得回到第一段里说的,因为所有类都继承于Object,因此也就集成了equals方法,而StringBuffer这个类并没有重写也不能重写equals这个方法,也就是说他用的判定准则和Object是一样的,也是说他并不会像String一样把两个国籍是中国的人认为是同一个人,所以它的结果是false,为什么我要说是不能重写呢,因为通过API文档你可以看到StringBuffer的定义是finall的,也就是这个类既不能被修改也不能被继承,所以你无法重写或者通过集成重写他的equals方法。

 

  不知道我的讲述大家看懂没有,下面留两个个小例子,请有兴趣的朋友试着分析分析结果,可以直接拷贝下来编译下。

 

Demo1:

 1 class Cat(){
 2     private String name;
 3     private String color;
 4     private int age;
 5 
 6     public Cat(String name,Sting color,int age){
 7         this.name = name;
 8         this.color = color;
 9         this.age = age;
10     }
11 
12      //重写equals方法,大家可以网上搜如何重写
13     public boolean equals(Object obj){
14         if(obj instanceof Cat){
15             Cat cat = (Cat)obj;
16             return this.name.equals(cat.name)&&
17                        this.color.equals(cat.color)&&
18                        this.age == cat.age;
19         }else{
20             return super.equals(obj);
21         }
22     }
23 
24     //重写equals方法必须重写hashCode方法 
25     public int hashCode(){
26         return this.name.hashCode();
27     }
28 }
29 
30 
31 public class Demo1(){
32     public static void main(String[] args){
33         Cat cat1 = new Cat("Tom","red",10);
34         Cat cat2 = new Cat("Tom","red",10);
35         System.out.println(cat1.equals(cat2));
36     }
37 }

 

 

Demo2:

 1 class Cat(){
 2     private String name;
 3     private String color;
 4     private int age;
 5 
 6     public Cat(String name,Sting color,int age){
 7         this.name = name;
 8         this.color = color;
 9         this.age = age;
10     }
11 
12      //重写equals方法,大家可以网上搜如何重写
13     public boolean equals(Object obj){
14         if(obj instanceof Cat){
15             Cat cat = (Cat)obj;
16             return this.name == cat.name&&
17                        this.color == cat.color&&
18                        this.age == cat.age;
19         }else{
20             return super.equals(obj);
21         }
22     }
23 
24     //重写equals方法必须重写hashCode方法 
25     public int hashCode(){
26         return this.name.hashCode();
27     }
28 }
29 
30 
31 public class Demo2(){
32     public static void main(String[] args){
33         Cat cat1 = new Cat("Tom","red",10);
34         Cat cat2 = new Cat("Tom","red",10);
35         Cat cat3 = new Cat(new String("Tom"),"red",10);
36         Cat cat4 = new Cat(new String("Tom"),"red",10);
37         System.out.println(cat1.equals(cat2));
38         System.out.println(cat3.equals(cat4));
39     }
40 }

 

posted @ 2012-08-30 10:19  tf_swufe  阅读(222)  评论(0编辑  收藏  举报