关于Java中使用List或Map中的contains或containsKey方法判断自定义对象

对于普通Java类型

1
2
3
4
5
6
7
8
9
10
List<String> testList = new ArrayList<>();
testList.add("A");
testList.add("B");
testList.add("C");
String newStr = "A";
if (testList.contains(newStr)){
return "exist";
}else {
return "no exist";
}

但对于自定义类型,直接使用contains方法不能达到预期效果:

1
2
3
4
5
6
7
8
9
10
List<User> testList = new ArrayList<>();
testList.add(new User(1,"A"));
testList.add(new User(2,"B"));
testList.add(new User(3,"C"));
User newUser = new User(1,"A");
if (testList.contains(newUser)){
return "exist";
}else {
return "no exist";
}

这种情况下,返回no exist。

观察List中contains方法源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
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;
}

从源码中可以看到,contains方法调用indexOf方法,并使用了equals来判断是否相等。

关于equals:

equals在比较字符串是与==是有区别的(因为String也重写了equals),具体这里不再说明。但是对比object对象是的效果与==是一致的。

1
2
3
public boolean equals(Object obj) {
return (this == obj);
}

重写equals:

根据以上源码,我们知道用contains比较自定义对象时,不能直接使用,需要重写equals方法。

1
2
3
4
5
6
7
8
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return userId.equals(user.userId) &&
userName.equals(user.userName);
}

若使用ieda,可以直接generate出这个方法并重写,不需要手写。

*重写hashcode: *

关于为什么在重写equals方法时要同时重写hashcode方法,应该都已经有所了解,这里简单引用一下。

hashCode()与 equals()的相关规定

  1. 如果两个对象相等,则 hashcode 一定也是相同的
  2. 两个对象相等,对两个对象分别调用 equals 方法都返回 true
  3. 两个对象有相同的 hashcode 值,它们也不一定是相等的
  4. 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
1
2
3
4
@Override
public int hashCode() {
return Objects.hash(userId, userName);
}

通用可以使用idea自动生成。

至此,使用contains方法判断自定义对象就可以正常使用了。

Map中的containsKey方法同理,以下记录一下真实的使用情况(可无视):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Data
public class BatchStationOilConcessionsFilter {

private String shopId;

private String goodsId;

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BatchStationOilConcessionsFilter that = (BatchStationOilConcessionsFilter) o;
return Objects.equals(shopId, that.shopId) &&
Objects.equals(goodsId, that.goodsId);
}

@Override
public int hashCode() {
return Objects.hash(shopId, goodsId);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void dataFilter(List<BatchStationOilConcessionsDTO> batchStationOilConcessionsDTOList){
List<Integer> list = new ArrayList<>();

// 必须保证顺序
Map<BatchStationOilConcessionsFilter, Date> map = new LinkedHashMap<>();

// 把shopId和goodsId存进batchStationOilConcessionsFilterList
for (BatchStationOilConcessionsDTO batchStationOilConcessionsDTO : batchStationOilConcessionsDTOList){
BatchStationOilConcessionsFilter batchStationOilConcessionsFilter = new BatchStationOilConcessionsFilter();
try {
BeanUtils.copyProperties(batchStationOilConcessionsFilter, batchStationOilConcessionsDTO);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}

if (map.containsKey(batchStationOilConcessionsFilter)){
// 记录index,后面删除
list.add(batchStationOilConcessionsDTO.getIndex());
}else{
map.put(batchStationOilConcessionsFilter, new Date());
}

}

System.out.println("重复的:" + list);

}