《Java程序员面试宝典》P99例题3的一个问题分析

来源:互联网 发布:奢侈品软件 编辑:程序博客网 时间:2024/04/29 21:43
在java程序员面试宝典中有这样一道题

面试例题3:The code output(下列代码输出结果是什么?)

import java.util.*;public class Test{private String value = null;public Test(String v){value = v;}public boolean equals(Test o){if(o == this){return true;}if(o instanceof Test){Test test = (Test)o;return value.equals(test.value);}return false;}public static void main(String[] args){List list = new ArrayList();Test test1 = new Test("object");Test test2 = new Test("object");Test test3 = new Test("object");Object test4 = new Test("object");list.add(test1);System.out.println(list.contains(test2));System.out.println(test2.equals(test3));System.out.println(test3.equals(test4));}} 

答案是false true false,为什么觉得有问题,先看下解析:

第一个输出false是因为list.add(test1);在list放入的是test1,也就是“object”的内存地址,而不是“object”本身。所以这样肯定是输出false。

第二个输出true,很明显,按照题目的equals的执行顺序,结果是true。

第三个是false,是调用了Object的Equals方法。

这道题困惑了我很久。因为我一直没有明白的是第三个为什么调用了Object的Equals方法,因为个人感觉test3.equals调用的是String.equals()方法;后来我加上了测试语句,代码如下。

import java.util.*;public class Test{private String value = null;public Test(String v){value = v;}public boolean equals(Test o){if(o == this){System.out.println("o == this");//test1return true;}if(o instanceof Test){Test test = (Test)o;System.out.println("o instanceof Test"); //test2return value.equals(test.value);}return false;}public static void main(String[] args){List list = new ArrayList();Test test1 = new Test("object");Test test2 = new Test("object");Test test3 = new Test("object");Object test4 = new Test("object");list.add(test1);System.out.println(list.contains(test2));System.out.println(test2.equals(test3));System.out.println(test3.equals(test4));}} 
运行之后,输出如下图:

发现只输出了一句"o instanceof Test",然后就开始思考,后来去百度了下资料,参考了http://blog.csdn.net/witsmakemen/article/details/7323604这篇博文,是关于ArrayList的contains这个方法的实现方式,ArrayList的源码如下:

public boolean contains(Object o) {return indexOf(o) >= 0;    } public int indexOf(Object o) {if (o == null) {    for (int i = 0; i < size; i++)if (elementData[i]==null)    return i;} else {    for (int i = 0; i < size; i++)if (o.equals(elementData[i]))    return i;}return -1;    }

也就是说,ArrayList会调用传进来的对象的equals()方法与list里面的元素逐个作比较,所以说解析中的第一句话:“第一个输出false是因为list.add(test1);在list放入的是test1,也就是“object”的内存地址,而不是“object”本身。” 并不是很合理,因为list.contains(test2)会调用test2的equals而在ArrayList的源码中我们可以看出contains(Object o)这个方法传递的是Object对象,相当于Object o = test2;但是我们这个时候会考虑多态的存在,即父类引用指向之类对象,但是请擦亮眼睛,我回到一开始那个程序,看看Test的equals方法:
public boolean equals(Test o){if(o == this){return true;}if(o instanceof Test){Test test = (Test)o;return value.equals(test.value);}return false;}

这个并没有重写他的父类Object的equals方法,Object中应该是这样public boolean equals(Object  o);所以不存在多态中方法调用的问题,也不能算是方法的重载,因为它们不是发生在同一个类内部,最多是写了一个新方法。到这里已经思路已经很清晰了吧。一开始我就陷入了方法重写的误区,后来去看了Object的API才发现自己搞错了,原谅我的才疏学浅。

所以这个问题应该这样解释:

第一个输出false是因为list.contains(test2)中test2是作为Object传递进来的,而且Test这个类没有对Object中的equals方法进行重写,所以调用的是它的父类Object的equals方法,Object中的equals方法是==比较,比较的还是元素的引用,list中只有test1的引用,所以输出false。

第二个输出true,这个比较明显,调用了题目中的Test的equals。

第三个输出false,是因为test3.equals(test4)这个方法中,test4的类型是Object,在Test中找不到equals(Object o)的方法,所以去super中即父类找,父类是Object,于是调用父类的equals(Object o)方法,所以还是调用test3父类Object的equals方法,比较的还是引用,所以是false。

最后,我们证明一下,我们稍微改动一下equals方法,如程序所示:

import java.util.*;public class Test{private String value = null;public Test(String v){value = v;}public boolean equals(Object o){  //这里我们将参数Test o改成Object oSystem.out.println("load equals()");if(o == this){System.out.println("o == this");return true;}if(o instanceof Test){Test test = (Test)o;System.out.println("o instanceof Test");return value.equals(test.value);}return false;}public static void main(String[] args){List list = new ArrayList();Test test1 = new Test("object");Test test2 = new Test("object");Test test3 = new Test("object");Object test4 = new Test("object");list.add(test1);System.out.println(list.contains(test2));System.out.println(test2.equals(test3));System.out.println(test3.equals(test4));}} 
运行结果如图:


这个程序中我们对Object的equals方法进行了重写,并且父类引用指向了子类对象,所以就存在了多态的问题,所以contains()方法调用了Test中的equals(),所以输出三个都是true。

因为基础不扎实,所以这个小问题困扰了我一下午,后面查了很多资料,看了一些博文,才发现问题所在,看了一半《java程序员面试宝典》这本书,个人感觉很多地方还是有一些错误的,很不靠谱,建议读者要持怀疑的态度去看。

0 0
原创粉丝点击