黑马程序员技术交流社区

标题: 为什么remove会依赖元素中的equals方法 [打印本页]

作者: 雷楚光    时间: 2012-2-21 19:10
标题: 为什么remove会依赖元素中的equals方法
这段代码看不懂,为什么结果是ture啊。主要不懂的是:remove方法底层也是依赖于元素的equals方法。什么意思?

import java.util.*;
class Person
{
        private String name;
        private int age;
        Person(String name,int age)
        {
                this.name = name;
                this.age = age;
        }
       
        public boolean equals(Object obj)
        {
                Person p = (Person)obj;
                return this.name.equals(p.name) && this.age == p.age;
        }
}
class ArrayListTest
{
        public static void sop(Object obj)
        {
                System.out.println(obj);
        }
        public static void main(String[] args)
        {
                ArrayList al = new ArrayList();
                al.add(new Person("lisi03",33));
                sop(al.remove(new Person("lisi03",33)));
                //remove方法底层也是依赖于元素的equals方法。
        }
}
作者: 李晓俊老师    时间: 2012-2-21 19:38
如果是判断集合是否包含某个对象元素,即contians方法的底层就调用对象equals的方法进行比较的,,这点你应该知道;;
其实集合在删除一个对象元素时是先判断是否有该元素,,它将该元素和自己的所有元素用equals都比较了一下,,才判断的,
如果有就删除成功,返回true,,反之返回false..对于基本数据类型的集合,,不需要重写equals方法,,因为他们能根据ASCII码表进行
比较,直接返回的就是比较后的结果,,,不过对于更复杂的对象元素,,,如Person,它包含name和age属性,,所以不能按照默认的equals
进行判断,我们必须重写equals方法,,,return this.name.equals(p.name) && this.age == p.age;
这句就是判断两个Person对象的,,如果name和age都相同就返回true,,反之返回false
作者: 吴璞玉    时间: 2012-2-21 19:48
remove方法是移除此列中首次出现的指定元素(如果它存在的话)
确切的说是移除满足(obj==null?get(i):obj.equals(get(i)))的最低索引的元素
底层是依靠equals方法来判断你所要移除的元素是否在列表中存在,而结果返回时true是因为remove方法的返回值为boolean类型,返回true代表此列表包含指定的元素。
作者: H07000223    时间: 2012-2-21 19:52
本帖最后由 H07000223 于 2012-2-21 19:58 编辑

对于这段代码,说说自己的理解吧
我认为,注释说的remove方法底层也是依赖于元素的equals方法应该是有道理的:

1.首先person类中重写了父类Object的equals方法,也就是说如果两个person实例的name和age属性相等的话,他们就是同一个对象,也就是内存地址相同。

2.然后当ArrayList中添加一个person类型元素,生成了一个新的person对象,开辟了一个新的内存空间。

3.调用ArrayList的remove方法,按照常理第二次new也会生成新的person对象,返回一个false。但是Person类重写了equals判断方法。
由于两次new的person对象的name和age一模一样,所以其实会指向同一个内存地址,两者其实是一回事。
我估计每次new一个对象,都会自动调用当前类的equals方法,看看是否已经存在该对象了,有了的话还生成干吗,没有的话自然生成一个新的

4.我想你也可以通过得到的结果反过来理解:
remove方法返回true就是说成功删除了该元素->也就是说两次new的是同一个对象->生成对象会自动调用equals方法进行是否存在的判断
作者: 唐溪永    时间: 2012-2-21 21:03
这是一个经典检查Remove与Equals 的方法

例子代码
  1. static void Main(string[] args)
  2.         {
  3.             List<A> list = new List<A>();
  4.             list.Add(new A(1, 1));
  5.             list.Add(new A(2, 2));
  6.             Console.WriteLine(list.Count);
  7.             list.Remove(new A(1, 1));
  8.             Console.WriteLine(list.Count);
  9.         }
复制代码
其实代码很简单,建立一个链表,增加2个元素,然后试图删除一个元素。在删除前后打印出链表中元素的个数.
然而结果却是:不一定!
问题的关键就是
list.Remove(new A(1, 1));
看似这句的企图是,删除第一个元素,那么它能达到这个目的吗?这要看看,list.Remove(T)的实现原理了,首先要检查链表中是否有这个元素,然后才能删除。那么,怎么确定是否有这个元素呢?

此方法使用用于 T(列表中的值的类型)的默认相等比较器 EqualityComparer(T).Default 来确定相等性。

那么我们看看这个EqualityComparer(T).Default 是什么?

返回一个默认的相等比较器,用于比较此泛型参数指定的类型。

Default 属性检查类型 T 是否实现此 System.IEquatable(T) 泛型接口,如果实现,该属性将返回一个使用该实现的 EqualityComparer(T)。否则,它返回一个使用 T 提供的 Object.Equals 和 Object.GetHashCode 的重写的 EqualityComparer(T)。

判断相等并不简单,如果什么都不做的话,默认会使用Object.Equals()函数判断相等。而我们知道Object.Equals()其实实现的是同一性比较,而不是相等性比较。所以只有两个引用变量指向同一个对象,才判定为相等。然而上述代码中,显然new A(1,1)返回的引用变量不可能指向链表中引用变量指向的对象,所以输出结果会是:

2

2

然而,如果我们的A,覆盖了Object的Equals函数,例如:
  1. class A
  2.     {
  3.         public int x;
  4.         public int y;
  5.         public A(int _x, int _y)
  6.         {
  7.             x = _x;
  8.             y = _y;
  9.         }
  10.         public static bool operator == (A a1, A a2)
  11.         {
  12.             Console.WriteLine("operator ==");
  13.             return (a1 == a2);
  14.         }
  15.         public static bool operator != (A a1, A a2)
  16.         {
  17.             return (a1 != a2);
  18.         }
  19.         public override bool Equals(object obj)
  20.         {
  21.             Console.WriteLine("override Equals");
  22.             if (this.x == ((A)obj).x && this.y == ((A)obj).y)
  23.                 return true;
  24.             else
  25.                 return false;
  26.         }
  27.     }
复制代码
那么输出结果将会是

2

1

所以,list.Remove(T)完全依赖于T的实现。上述代码也证明了,List.Remove(T)不会使用T的==操作符而是使用T的Equals()方法判断相等性。


希望以上会有帮助




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2