java容器中关于equals的重写

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java容器中关于equals的重写相关的知识,希望对你有一定的参考价值。

import java.util.*;

public class TestContainner

public static void main(String[] args)

Collection c = new HashSet();
c.add(new Name("lintong","wang"));
System.out.println(c.remove(new Name("lintong","wang")));





class Name

public String firstName;
public String lastName;

public Name(String firstName,String lastName)

this.firstName = firstName;
this.lastName = lastName;


public String toString()

return lastName + firstName;


public boolean equals(Object obj)

if(obj instanceof Name)

Name name = (Name)obj;
return (this.firstName.equals(name.firstName))&& (this.lastName.equals(name.lastName));

return super.equals(obj);



public int hashCode()

return firstName.hashCode();



为什么equals采用这种方式重写就能重写成功,但是当我把equals方法改成下面这种方法时就失败了?
public void equals(Name name)

return (this.firstName.equals(name.firstName))&&(this.lastName.equals(name.lastName));


已经明确了比较的就是个Name类对象,但是为什么采用这种方式比较,确输出false。
打错了 就算equals的返回值类型是boolean 返回的也是false

刚才试验了下你说的public void equals(Name name)返回为false,其实这句话本身编译就不通过的,一个返回void的方法怎么有boolean的返回值呢?如果你把void改成boolean例如
public boolean equals(Name name)

return (this.firstName.equals(name.firstName))&&(this.lastName.equals(name.lastName));

这个方法一样是返回true的。但是就如楼下所说,既然是重写,肯定是按照Object类equals的方法,参数是Object,不然这就不叫重写,叫做重载了!追问

我把int改为boolean之后 仍然返回false

追答

不知道你是怎么测试相不相等的。
我是直接实例了两个name,n1和n2.
用System.out.println(n1.equals(n2));
不管是重写还是重载都是是对的。
楼主可以给n1和n2用相同的构造方法试试我说的。

以下是改了你的main方法部分:
public static void main(String[] args)

Name n1=new Name("1","1");
Name n2=new Name("1","1");
System.out.println(n1.equals(n2));


输出为true.

如果一个类里有多个方法名相同的方法,叫做重载,因为继承的Object的equals的参数Obj和你的这个Name是不一样的。只有完全和父类的方法相同,才叫做重写,也叫覆盖。当你的参数不是Name类型,是一个Obj类型,那么你用重载相当于没用重写,程序会认为你调用的父类的equals,所以肯定是false.所以楼主应该用了obj的参数吧,你用Name型的就是true了。

参考技术A equals方法没有进行重写,建议先打出equals ,然后按eclipse快捷键,一般会设置成 alt+\的那个,自动生成,然后修改方法体 参考技术B public void equals(Name name) 不是Object的方法的覆盖。

public boolean equals(Object obj) 则是追问

打错了 就算是boolean 返回值也是false

追答

参数不同 ~

追问

什么意思 发送的就是一个Name类型的对象啊

追答

public void equals(Name name) 不是Object的方法的覆盖。

public boolean equals(Object obj) 则是

追问

形参的类型不一样 不构成重写?

追答

是的

~~

参考技术C 返回值类型不对,不是重写

java集合

 

 1、关于hashCodeequals的处理

 1.1为什么在重写了equals()方法之后也必须重写hashCode()方法

 java中,所有的对象都是继承于object类,object类有两个方法equals,hashCode.

 1)在没有重写equals方法,我们的类是继承了object的equals方法,object比较的                       是两个对象的内存地址,如果new了两个对象内存地址肯定不一样:

     对于值对象,== 比较的是两个对象的值

     对于引用对象,比较的是两个对象的地址

 2)hashcode主要为散列表

  如果一个对象的equals没有被改写,那么在执行时无论调用多少次hashCode()总是   返回相同的值(对象的内部地址转化为该数值)。

如果两个对象相等(equals相等),那么对应的hashCode也相等。

两个对象不相等(equals不相等),其对应的hashCode也不相等,这种规范不是必须的(亦即两个对象不相等,其对应的hashCode可能相等)。延伸理解,hashCode相等的两个对象不一定相等(equals相等)。但是建议遵守为两个不同对象返回不同的散列码的规范(比如重写时,但是Object.hashCode()确实为不同的对象返回不同的hashCode), 这种可以提升hash tables的性能。

  

2.一般如果使用java中的map对象进行存储的时候,他会自动调用hashcode方法来比较两个对象是否相等。

1)重写equals方法时需要重写hashCode方法,主要是针对Map、Set等集合类型的使用;

   a: Map、Set等集合类型存放的对象必须是唯一的;

   b: 集合类判断两个对象是否相等,是先判断HashCode返回值是否ture,在判断equals是否返回TRUE,只有两者都返回ture,才认为该两个对象是相等的。

 2)、由于Object的hashCode返回的是对象的hash值,所以即使equals返回TRUE,集合也可能判定两个对象不等,所以必须重写hashCode方法,以保证当equals返回TRUE时,hashCode也返回Ture,这样才能使得集合中存放的对象唯一。

2.ArrayListsubList结果不可强制转换成ArrayList.

//ArrayList数组表的subList()方法截取的是同内存一个片段,

//在截取后返回新的ArrayList数组表增加、删减、排序,都会对原数组表产生影响!

//下面是源码

//    SubList(AbstractList<E> parent,

//            int offset, int fromIndex, int toIndex) {

//        this.parent = parent;

//        this.parentOffset = fromIndex;

//        this.offset = offset + fromIndex;

//        this.size = toIndex - fromIndex;

//        this.modCount = ArrayList.this.modCount;

//    }

//  public void add(int index, E e) {

//         rangeCheckForAdd(index);

//         checkForComodification();

//         parent.add(parentOffset + index, e);

//         this.modCount = parent.modCount;

//         this.size++;

//     }

//

//     public E remove(int index) {

//         rangeCheck(index);

//         checkForComodification();

//         E result = parent.remove(parentOffset + index);

//         this.modCount = parent.modCount;

//         this.size--;

//         return result;

//     }

 

    public static void main(String[] args){

        List<String> list = new ArrayList<String>();

        list.add("fei");

        list.add("long");

        list.add("feiong");

        list.add("飞天奔月");

        List<String> listSub = list.subList(1, 3);

        System.out.println("listSub"+listSub);//listSub[long, feiong]

        System.out.println("list :"+list);//list :[fei, long, feiong, 飞天奔月]

        listSub.add("hhhaahha");

        System.out.println("listSub"+listSub);//listSub[long, feiong, hhhaahha]

        System.out.println("list :"+list);//list :[fei, long, feiong, hhhaahha, 飞天奔 ]

        //listSub的第一个删除了

        //list中的同样的元素也删除了

        listSub.remove(0);

        System.out.println("listSub"+listSub);//listSub[feiong, hhhaahha]

        System.out.println("list :"+list);//list :[fei, feiong, hhhaahha, 飞天奔月]

        

        

       //父列表不能删除SubList中的首个元素了--因为offset不能更改

        //list.remove(0);

        list.remove(3);

        System.out.println("listSub"+listSub);//报出异常

}

3.使用集合转数组时,必须集合的toArray(T[] array) 传入的是类型完全一样的数组大小

    

   @Test

public void test(){

Long[] a = {1L, 2L, 3L, 4L};

 

        List<Long> list = new ArrayList<Long>();

        list.add(4L);

        list.add(5L);

        System.out.println("a" + a);//a[Ljava.lang.Long;@4ee00c09

        //当入参的a.size > list.length,在a上面修改,并且在a[list.size] == null

        a = list.toArray(a);

        System.out.println("a" + a);//a[Ljava.lang.Long;@4ee00c09

       

 

        Long[] b = {1L};

 

        //当入参的a.size < list.length,返回值是新建的一个数组

        list.toArray(b);

        System.out.println("b" + b);//b[Ljava.lang.Long;@68111f9b

        b=list.toArray(b);

        System.out.println("b" + b);//b [Ljava.lang.Long;@3c322e7d

 

}

4.使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法 (根据源码得知asList返回的是内部定义的ArrayList,它并没有实现增删改查方法)

   @SafeVarargs

    public static <T> List<T> asList(T... a) {

        return new ArrayList<>(a);

    }

 

    /**

     * @serial include

     */

    private static class ArrayList<E> extends AbstractList<E>

        implements RandomAccess, java.io.Serializable

    {

        private static final long serialVersionUID = -2764017481108945198L;

        private final E[] a;

 

        ArrayList(E[] array) {

            if (array==null)

                throw new NullPointerException();

            a = array;

        }

 

        public int size() {

            return a.length;

        }

 

        public Object[] toArray() {

            return a.clone();

        }

 

        public <T> T[] toArray(T[] a) {

            int size = size();

            if (a.length < size)

                return Arrays.copyOf(this.a, size,

                                     (Class<? extends T[]>) a.getClass());

            System.arraycopy(this.a, 0, a, 0, size);

            if (a.length > size)

                a[size] = null;

            return a;

        }

 

        public E get(int index) {

            return a[index];

        }

 

        public E set(int index, E element) {

            E oldValue = a[index];

            a[index] = element;

            return oldValue;

        }

 

        public int indexOf(Object o) {

            if (o==null) {

                for (int i=0; i<a.length; i++)

                    if (a[i]==null)

                        return i;

            } else {

                for (int i=0; i<a.length; i++)

                    if (o.equals(a[i]))

                        return i;

            }

            return -1;

        }

 

        public boolean contains(Object o) {

            return indexOf(o) != -1;

        }

}

5.java 集合中泛型通配符 用了之后就不能添加 元素了 为什么?

//通配符只能出现在引用的定义中,而不能出现在创建对象中。例如:new ArrayList<?>(),这是不可以的。ArrayList<?> list = null,这是可以的。

public static  void fun(List<?> list){

//list.add(list.get(0)); 编译不通过

System.out.println("已经打印了"+list);

}

    

//1.通配符的上届: Anilmal,Cat,dog

//   

//   public static void act(List<? extends Anilmal> list) {

//    for (Anilmal anilmal : list) {

//     animal.eat();

//          list.add(new Animal("animal")); //编译不通过

//          list.add(new Bird("bird"));//编译不通过

//          list.add(new Cat("cat"));//编译不通过

//     }

//“? extends Animal”则表示通配符“?”的上界为Animal,换句话说就是,“? extends Animal”可以代表Animal或其子类,可代表不了Animal的父类(如Object),因为通配符的上界是Animal

//三个“add”操作都可能引发类型不兼容问题,而传入的参数是未知的,所以java为了保护其类型一致,禁止向List<? extends Animal>添加任意对象,不过却可以添加null,即list.add(null)是可行的  

//2.通配符的下届

//既然有了通配符的上界,自然有着通配符的下界。可以如此定义通配符的下界 List<? super Bird>,其中”Bird“就是通配符的下界   

//为了保护类型的一致性,因为“? super Bird”可以是Animal,也可以是Object或其他Bird的父类,//因无法确定其类型,也就不能往List<? super Bird>添加Bird的任意父类对象。

// 既然法无确定其父类对象,那该如何遍历List<? super Bird> ? 因为Object是所有类的根类,所//以可以用Object来遍历

 

6.for循环删除(ArrayList.remove

 

for循环的时候是不允许删除list对象的。

因为ArrayList的父类AbstractList里有个modCount的字段记录着List的总数,for循环的时候如果增加或者删除了元素,(修改不会影响),此字段会变化,那么在下次for循环的时候检查到跟之前的长度不同,此时会报ConcurrentModificationException异常。

解决办法是一般用Iterator遍历

 

以上是关于java容器中关于equals的重写的主要内容,如果未能解决你的问题,请参考以下文章

重写了equals方法为何需要重写 hashCode

Java中关于equals()和hashCode()的问题

第十七章 Java的容器

第十七章 Java的容器(Map)

Java中的equals和hashCode方法

java中关于重载与重写的区别