程序如下:
import java.util.*;
class Test2{
int i; Test2(int i)
{
this.i=i;
} int geti()
{
return i;
} public String toString()
{
return Integer.toString(i);
} public boolean equals(Test2 p)
{
        return p.geti()==this.i;
}

}
class Test
{

public static void main(String [] args){
ArrayList <Test2> strList=new ArrayList<Test2>();
Test2 pp=new Test2(0);
strList.add(new Test2(1));
strList.add(new Test2(2));
strList.add(new Test2(3));
strList.add(pp);
        System.out.println(pp.equals(new Test2(0)));
System.out.println(strList.indexOf(new Test2(1)));
System.out.println(strList.indexOf(pp));
System.out.println(strList);

}
}问题:红色的两行代码,为什么第一行能够返回true,而第二行不能返回index值?equals方法重载后想实现以值来比较两个对象是否相等,这样写对吗?

解决方案 »

  1.   

    建议这样试一下:
    test2 tt = new test2(1);
    System.out.println(strList.indexOf(tt)); 
      

  2.   

    public static void main(String[] args){
    Test2 t1 = new Test2(1);
    Test2 t2 = new Test2(2);

    List list = new ArrayList();
    list.add(t1);
    list.add(t2);
    Test2 t3 = new Test2(2);
    System.out.println(list.indexOf(t1));刚才试了一下,这样好像能找到原因可能是因为NEW一个对象后,已是一个新的对象引用了。。
      

  3.   

    泛型是实现是擦除的,即在编译期检查,在运行期已经扔掉了对象的类型,所以Test2(1),Test2(2),Test2(3)
    在运行期只是Object,equals比较没法相等。
      

  4.   

    这个和类型擦除没有关系,关键是你并没有重写equals方法
    你看看object的equals方法的参数是什么,是object而不是Test2,你只是
    重载了该方法。
      

  5.   

    你这样子肯定能找到的,不过我想通过重载equals,然后通过自己定义的相等来返回indexof值,不知道怎么整
      

  6.   

    list 的indexOf方法
    返回:
     (o==null ? get(i)==null : o.equals(get(i)))
    因为你没有重写equals,所以这里调用的依然是
    object的equals方法,所以没有该值!
      

  7.   


    怎么会有类型擦除没有关系?这完全就是类型擦除引起的。
    因为list中的元素在运行时失去了Test2类型,而变成了Object类型。
    所以indexOf时调用的equals(Object o)而不是equals(Test2 t).
    而没有重新实现的equals(Object o)仅比较句柄相同,new对象肯定不相等,所以indexOf返回-1而本楼的代码因为在运型期有确定的类型,所以调用的是equals(Test2 t)所以能找到。这根本就是因为泛型在运行期失去了原始类型引起的,竟然叫没有关系?
      

  8.   

    改掉Equals方法public boolean equals(Object p) 

    if(this==p){
    return true;
    }
    if(p==null){
    return false;
    }
    if(p.getClass()==this.getClass()){
    Test2 t=(Test2)p;
    return t.geti()==this.i;
    }else{
    return false;
    }

      

  9.   

    out:
    true
    0
    3
    [1, 2, 3, 0]
      

  10.   

    问题解决了,主要是equals方法没有实现重写,我本以为原帖那样就已经重写了,代码改成一下即可:
    public boolean equals(Object p)
    {
    Test2 uu=(Test2)p;
            return uu.geti()==this.i;
    }
    顺便问一下,那个hashcode跟equals联系很紧密吗?
    10楼和11楼都是高手
      

  11.   

    楼主已经明确说了是重载了equals方法,给个对象重载equals的强类型方法可以极大地提高性能。这楼主的目的已经非常明确,对于Test2类型的比较我不想用equals(Object o)而用equals(Test2 t)
    但这里他没有控制储参数类型的匹配,把失去原始类型的对象传进去了。
      

  12.   

    这个是Arraylist的indexOf的源码。    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;
        }
      

  13.   

    这个已经是正解了,才开始我把重载跟重写搞混了。但是indexof里面的语句o.equals(elementData[i])为什么不调用我自己重载的那个equals方法?在这里elementData[i]是Test2类型的啊,应该调用我重载的那个方法才对啊
      

  14.   

    楼主的主题是楼主已经明确知道自己在重载equals,如果象上面那样实现的话就是普通的equals实现,
    即覆盖Object的实现。和楼主的主题不是一回事了。只是为了防止类型丢失时也能正确工作,在重载equals时要将原来的equals和重载后的euqals有共同的行为。
    但重在一个强类型的equals在有时是必要的,在强类型下可以获得较大的性能。
      

  15.   

    两位大侠再说说啊,为什么不调用我的那个equals方法?在ArrayList里面的对象失去了它本身的类型吗?那我通过System.out.println(strList.get(1).getClass());
    语句为什么得到Test2这个结果呢?这说明list里面的对象没有丢失自己的类型啊,应该调用我重载的equals方法啊,也就是楼上说的强类型的equals方法啊,否则怎么防止类型丢失?最好写出来代码看看啊
      

  16.   

    当辨别对象本身时,泛型容器中保存的是对象的引用,它看的是引用的类型。
    即在容器中其实是list中其实是Object o1 = new Test2();
    所以调用了你的equals(Object o)的版本的方法。
    但在一个对象上调用方法时,是动态绑定的,也就是多态性在保证它getClass()的方法是实际对象的。其实你只要在外面试一下就行了:Object o = new Test2(100);Test2 t = new Test2(100);
    t.equals(o);//调用原始版本。
    o.equals(t);调用你的重载版。
    至于如何保证类型在泛型中不丢失?没有方法,泛型 就是在编译期实现的,运行期被擦除了。除非你用数组,
    它是协变类型的。