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 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了。
public boolean equals(Object obj) 则是追问
打错了 就算是boolean 返回值也是false
追答参数不同 ~
追问什么意思 发送的就是一个Name类型的对象啊
追答public void equals(Name name) 不是Object的方法的覆盖。
public boolean equals(Object obj) 则是
形参的类型不一样 不构成重写?
追答是的
~~
java集合
1、关于hashCode和equals的处理
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.ArrayList的subList结果不可强制转换成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的重写的主要内容,如果未能解决你的问题,请参考以下文章