1. Collection集合
集合是Java中的一种容器,可以存储多个数据,类似于数组,但是和数组又不一样
数组:存放元素的数据类型要相同;
存储元素的长度一定
集合:动态的存储多个对象
动态:支持动态扩容
对象:存储类的实例,当存储基本数据类型时也会变为包装类对象
2. Collection常用的方法
集合的contains、equals、remove方法底层都是调用了元素对象的equals方法进行比较执行的。
add、addAll:添加元素方法
/**
* 自定义类
*/
class Person {}
Collection col1 = new ArrayList();
// 因为没有指定集合中的数据类型,则默认为Object,如果传入666,则会发生向上转型:int->Integer->Object
col1.add(666);
col1.add(true);
col1.add("abc");
col1.add(new Person());
Collection col2 = new ArrayList();
col2.add(1);
col2.add(2);
col2.add(new Person());
col1.addAll(col2);
// 集合重写了toString方法,可以直接打印
System.out.println("col1: " + col1);
//结果
col1: [666, true, abc, com.study.part3.Person@2b, 1, 2, com.study.part3.Person@2b]
clear:清空集合
Collection col1 = new ArrayList();
// 因为没有指定集合中的数据类型,则默认为Object,如果传入666,则会发生向上转型:int->Integer->Object
col1.add(666);
col1.add(true);
col1.add("abc");
col1.add(new Person(12));
Collection col2 = new ArrayList();
col2.add(1);
col2.add(2);
col2.add(new Person(12));
col1.addAll(col2);
// 集合重写了toString方法,可以直接打印
System.out.println("col1: " + col1);
// 清空集合
col1.clear();
System.out.println("clear之后的col1: " + col1);
// 结果
col1: [666, true, abc, com.study.part3.Person@2b, 1, 2, com.study.part3.Person@2b]
clear之后的col1: []
contains:是否包含某个元素
底层调用元素对象的equals方法进行比较
/**
* 自定义类
*/
class Person {
Integer age;
public Person(Integer age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(age, person.age);
}
@Override
public int hashCode() {
return Objects.hash(age);
}
}
Collection col1 = new ArrayList();
// 因为没有指定集合中的数据类型,则默认为Object,如果传入666,则会发生向上转型:int->Integer->Object
col1.add(666);
col1.add(true);
col1.add("abc");
col1.add(new Person(12));
// 集合重写了toString方法,可以直接打印
System.out.println("col1: " + col1);
// 是否包含某个元素,如果集合中有引用类型,则会调用引用类型的equals方法进行内容比较
boolean contains = col1.contains("abc");
System.out.println("是否包含abc: " + contains);
// 如果没有重写equals方法,则equals方法默认比较的是内存地址,则就会返回false
boolean contains2 = col1.contains(new Person(12));
System.out.println("是否包含12岁的Person: " + contains2);
// 结果
col1: [666, true, abc, com.study.part3.Person@2b]
是否包含abc: true
是否包含12岁的Person: true
remove:移除某个元素,只会移除匹配到的第一个元素,即使存在多个相同元素,也只会移除一个
底层调用元素对象的equals方法进行比较
/**
* 自定义类
*/
class Person {
Integer age;
public Person(Integer age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(age, person.age);
}
@Override
public int hashCode() {
return Objects.hash(age);
}
}
Collection col1 = new ArrayList();
// 因为没有指定集合中的数据类型,则默认为Object,如果传入666,则会发生向上转型:int->Integer->Object
col1.add(666);
col1.add(true);
col1.add("abc");
col1.add(new Person(12));
Collection col2 = new ArrayList();
col2.add(1);
col2.add(2);
col2.add(new Person(12));
col1.addAll(col2);
// 集合重写了toString方法,可以直接打印
System.out.println("col1: " + col1);
// 移除某个元素,底层也是调用了对象的equals方法进行比较,只会移除匹配的第一个元素,即使集合中有多个相同元素,也只会移除一个
boolean remove = col1.remove(new Person(12));
System.out.println("是否移除成功: " + remove);
System.out.println(col1);
// 结果
col1: [666, true, abc, com.study.part3.Person@2b, 1, 2, com.study.part3.Person@2b]
是否移除成功: true
[666, true, abc, 1, 2, com.study.part3.Person@2b]
equals:如果和集合进行比较,则比较的就是集合中的元素内容是否相等
底层调用元素对象的equals方法进行比较
/**
* 自定义类
*/
class Person {
Integer age;
public Person(Integer age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(age, person.age);
}
@Override
public int hashCode() {
return Objects.hash(age);
}
}
Collection col2 = new ArrayList();
col2.add(1);
col2.add(2);
col2.add(new Person(12));
// 比较两个集合是否相等,比较的是元素内容。如果集合中有引用类型,则会调用引用类型的equals方法进行内容比较
Collection col3 = new ArrayList();
col3.add(1);
col3.add(2);
col3.add(new Person(12));
boolean equals = col2.equals(col3);
// 因为重写了Person类的equals方法,所以为true,若不重写,则比较的是每个元素的内存地址,则person这个元素肯定不相等,则就会返回false
System.out.println("比较两个集合是否相等: " + equals);
// 结果
比较两个集合是否相等: true
3. 源码剖析-集合对equals方法的使用
contains方法:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
进入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++)
// 调用元素对象的equals方法进行比较,如果相同则返回对应的索引位置
if (o.equals(elementData[i]))
return i;
}
return -1;
}
remove方法:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
总结:
Collection集合中的remove方法和contains方法底层都会调用equals;因为对对象的地址的比较没有什么意义,我们实际上需要的是对象内容间的比较;所以在有一些情况下我们就需要重写equals方法。