将自定义对象存入到HashSet集合中并去除重复元素

HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。

注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。

HashSet加入的对象需要重写hashCode方法和equals方法,因为对于自定义类需要提供判断怎样才算重复元素的方法。
本例中的hashCode方法和equals方法即是用来判断student对象是否为重复对象的标准方法。

package tan;
import java.util.HashSet;
import java.util.Iterator;
class Student{
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name:"+name+"age:"+age;
}
//HashSet加入的对象需要重写hashCode方法和equals方法,因为对于自定义类需要提供判断怎样才算重复元素的方法。
//本例中的hashCode方法和equals方法即是用来判断student对象是否为重复对象的标准方法。
@Override
public int hashCode() {
System.out.println(this.name+"....hashCode");
return name.hashCode()+age*25;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Student)){
return false;
}
Student student=(Student)obj;
System.out.println(this.name+"...equals...."+student.name);
return this.name.equals(student.name)&& this.age==age;
}
}
public class HashSetTest {
public static void main(String[] args) {
HashSet hs=new HashSet();
hs.add(new Student(20,"tan1"));
hs.add(new Student(21,"tan2"));
hs.add(new Student(22,"tan3"));
// hs.add(new Student(20,"tan1"));
hs.add(null);//HashSet中可以添加null值
System.out.println(hs.contains(new Student(21, "tan2"))); 
//删除元素
hs.remove(new Student(21, "tan2"));
Iterator it=hs.iterator();
while(it.hasNext()){
Object obj=it.next();
if(obj==null){
System.out.println(obj);
continue;
}else{
Student s=(Student)obj;
System.out.println("name:"+s.getName()+" "+"age:"+s.getAge());
}
}
}
}

结果为:tan1…hashCode
tan2…hashCode
tan3…hashCode
tan2…hashCode
tan2…equals…tan2
true
tan2…hashCode
tan2…equals…tan2
null
name:tan1 age:20
name:tan3 age:22

<think> 我们正在讨论如何去除List对象集合中的相同元素(即去重)。根据用户提供的引用资料,有多种方法可以实现,具体取决于"相同元素"的定义(引用相等还是内容相等)以及去重时的具体需求(例如是否需要对某些属性进行合等)。 用户提供的引用资料中展示了以下几种去重方法: 1. 引用[1]:使用Map,以对象的某个唯一属性(如物料型号)作为key,在遍历过程中合相同key的对象(例如将数量相加),最后将Map的values转为新的List。这种方法适用于需要合重复项的场景。 2. 引用[2]:利用Set的特性去重。但是要注意,使用Set去重需要对象正确重写hashCode和equals方法,这样才能根据对象的属性内容来判断是否重复。 3. 引用[3]:使用两层循环,遍历原List,将不重复的元素添加到新List中。这种方法效率较低(O(n^2)),不适合大数据量。 4. 引用[4]:也是使用Map,处理多个List合去重(根据某个属性),且在遇到重复时可以选择移除或覆盖。 根据用户当前的问题,他想要去除List对象集合里的相同元素。这里我们假设“相同”是指对象的内容相等(即属性值相等),而不是引用相等。因此,我们需要根据对象的内容来去重。 下面详细介绍几种常用的去重方法: ### 方法1:使用HashSet(基于引用[2]) 这是最简洁的方法,利用HashSet不存储重复元素的特性。但前提是对象必须正确重写hashCode和equals方法,以便Set可以根据对象的内容判断是否重复。 步骤: 1. 在对象类中重写hashCode和equals方法(例如,根据所有属性或关键属性生成hashCode和判断相等)。 2. 将List集合中的所有元素添加到HashSet中,自动去重。 3. 将HashSet转换回List。 示例代码: ```java // 假设我们有一个User类,需要根据id, name, age去重 public class User { private Integer id; private String name; private Integer age; // 构造方法、getter、setter省略 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(age, user.age); } @Override public int hashCode() { return Objects.hash(id, name, age); } } // 去重操作 List<User> listWithDuplicates = ...; // 原始列表 Set<User> set = new HashSet<>(listWithDuplicates); // 利用HashSet去重 List<User> listWithoutDuplicates = new ArrayList<>(set); // 转换回List ``` 优点:代码简洁,效率较高(O(n))。 缺点:需要重写hashCode和equals,且会改变元素顺序(HashSet不保证顺序)。 ### 方法2:使用LinkedHashSet(保持顺序) 如果希望去重后保留元素的原始顺序,可以使用LinkedHashSet。 示例代码: ```java Set<User> set = new LinkedHashSet<>(listWithDuplicates); List<User> listWithoutDuplicates = new ArrayList<>(set); ``` ### 方法3:使用Java 8 Stream API(推荐) 使用Java 8的Stream API可以更简洁地实现去重,且可以保持顺序。 示例代码: ```java List<User> listWithoutDuplicates = listWithDuplicates.stream() .distinct() .collect(Collectors.toList()); ``` 注意:使用`distinct()`方法同样需要对象重写hashCode和equals方法。 ### 方法4:使用Map(根据指定属性去重,如引用[1]和[4]) 有时,我们可能需要根据对象的某一个或多个属性来去重(而不是整个对象的所有属性),或者需要在去重的同时合一些属性(如求和)。这时可以使用Map。 示例场景:根据用户id去重,如果id相同则认为是同一个用户(其他属性可能不同,但我们只保留第一个或需要合)。 - 情况1:只保留第一个出现的重复元素 ```java Map<Integer, User> map = new LinkedHashMap<>(); // 用LinkedHashMap以保持顺序 for (User user : listWithDuplicates) { map.putIfAbsent(user.getId(), user); // 如果id尚未存在,则放入 } List<User> listWithoutDuplicates = new ArrayList<>(map.values()); ``` - 情况2:去重属性(如将年龄相加) ```java Map<Integer, User> map = new HashMap<>(); for (User user : listWithDuplicates) { if (map.containsKey(user.getId())) { User existingUser = map.get(user.getId()); existingUser.setAge(existingUser.getAge() + user.getAge()); // 合年龄 // 可以合其他属性... } else { map.put(user.getId(), user); } } List<User> listWithoutDuplicates = new ArrayList<>(map.values()); ``` ### 方法5:遍历比较(不推荐,效率低) 如引用[3]所示,使用两层循环遍历,将不重复的元素添加到新List中。这种方法效率低(O(n^2)),只适合小数据量。 示例代码: ```java List<User> newList = new ArrayList<>(); for (User user : listWithDuplicates) { if (!newList.contains(user)) { // 这里会调用equals方法,所以也要重写equals newList.add(user); } } ``` ### 总结 - **一般去重(整个对象内容相同)**:推荐使用`HashSet`、`LinkedHashSet`(保持顺序)或Java 8 Stream的`distinct()`方法,前提是重写hashCode和equals方法。 - **根据某个属性去重(不合)**:使用Map,以该属性为key,对象为value,使用`putIfAbsent`方法。 - **去重属性**:使用Map,遍历时进行合操作。 - **注意**:在选择方法时,考虑是否需要保持顺序以及性能要求。 根据用户的具体需求,选择合适的方法。如果用户没有重写对象的hashCode和equals方法,那么方法1、2、3、5将无法按内容去重(它们会退化成按引用去重)。因此,确保对象类正确重写了hashCode和equals方法至关重要。 §§相关问题§§ 1. 在Java中,如何正确重写对象的hashCode和equals方法? 2. 使用Java 8 Stream API进行去重时,如何根据对象的某个属性去重? 3. 如何对List中的对象根据多个属性去重? 4. 在去重的同时合属性,有哪些高效的方法? </think> ### 去除List对象集合中相同元素的常用方法 根据引用资料,去除List中重复对象的核心思路是**利用唯一标识或对象属性判断重复性**,以下是五种实用方法: #### 1. 基于Map的去重(推荐) 通过Map的key唯一性实现去重,支持属性合(如引用[1]): ```java // 1. 创建Map(以唯一属性为key) Map<String, YourObject> map = new HashMap<>(); for (YourObject obj : originalList) { String key = obj.getUniqueField(); // 如物料型号/ID if (map.containsKey(key)) { // 2. 重复时合属性(如数值相加) YourObject existing = map.get(key); existing.setValue(existing.getValue() + obj.getValue()); } else { // 3. 首次出现直接存入 map.put(key, obj); } } // 4. 转换回List List<YourObject> distinctList = new ArrayList<>(map.values()); ``` **适用场景**:需合重复项的属性(如统计求和)[^1] #### 2. 使用HashSet去重(需重写equals/hashCode) 利用Set天然去重特性(如引用[2]): ```java // 1. 重写对象类的equals和hashCode方法 public class YourObject { private String id; private int value; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; YourObject that = (YourObject) o; return Objects.equals(id, that.id); // 按ID判等 } @Override public int hashCode() { return Objects.hash(id); // 按ID生成哈希码 } } // 2. 使用HashSet去重 Set<YourObject> set = new HashSet<>(originalList); List<YourObject> distinctList = new ArrayList<>(set); ``` **关键点**:必须正确重写`equals()`和`hashCode()`,否则去重失效[^2] #### 3. Java 8 Stream API(简洁方案) ```java List<YourObject> distinctList = originalList.stream() .distinct() // 依赖equals/hashCode .collect(Collectors.toList()); ``` #### 4. 遍历对比去重(低效但简单) ```java List<YourObject> distinctList = new ArrayList<>(); for (YourObject obj : originalList) { // 检查新List是否包含相同对象(依赖equals方法) if (!distinctList.contains(obj)) { distinctList.add(obj); } } ``` **缺点**:时间复杂度O(n²),大数据量性能差[^3] #### 5. 多列表合去重(引用[4]) 合多个List移除重复项: ```java Map<String, YourObject> mergedMap = new HashMap<>(); // 合第一个List list1.forEach(obj -> mergedMap.put(obj.getKey(), obj)); // 处理第二个List for (YourObject obj : list2) { if (mergedMap.containsKey(obj.getKey())) { mergedMap.remove(obj.getKey()); // 移除重复项 } else { mergedMap.put(obj.getKey(), obj); // 添加新项 } } List<YourObject> result = new ArrayList<>(mergedMap.values()); ``` ### 方法对比表 | 方法 | 是否需要重写equals/hashCode | 是否支持属性合 | 时间复杂度 | 推荐场景 | |--------------------|----------------------------|------------------|------------|-----------------------| | **Map去重** | 否(依赖自定义key) | ✅ | O(n) | 需合重复项属性 | | **HashSet去重** | ✅ | ❌ | O(n) | 简单去重 | | **Stream distinct**| ✅ | ❌ | O(n) | Java8+简洁代码 | | **遍历对比** | ✅ | ❌ | O(n²) | 小数据集 | | **多列表合** | 否(依赖自定义key) | ✅ | O(n) | 合多个List去重 | ### 注意事项 1. **自定义相等逻辑**:业务中"相同对象"需明确定义(如ID相等或组合属性相等) 2. **哈希一致性**:使用HashSet时必须同时重写`equals()`和`hashCode()`(违反将导致集合操作异常)[^2][^4] 3. **线程安全**:多线程环境需改用`ConcurrentHashMap`或同步控制 4. **内存考虑**:大数据集优先选择O(n)方法(如HashMap),避免遍历对比 > 示例:用户对象按ID去重(引用[5]) > ```java > public class User { > private Integer id; // 作为唯一标识 > private String name; > private Integer age; > > // 重写equals和hashCode(仅依赖id) > @Override > public boolean equals(Object o) { > if (this == o) return true; > if (!(o instanceof User)) return false; > User user = (User) o; > return Objects.equals(id, user.id); > } > @Override > public int hashCode() { > return Objects.hash(id); > } > } > ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值