一,各个集合的特点:

  •   Collection(集合):容器,用于存放对象(引用类型。基本类型需要自动装箱)
  •   List(列表):元素有序,元素可以重复 (有索引)。 通过元素的equals()方法判断是否重复。
  •   Set(集):元素无序,不可重复 (没有索引)。 遍历只能用Iterator迭代器和增强for, 不能使用普通for遍历。
  •   ArrayList(数组列表): 查询快,增删慢。
  •   LinkedList(链表): 查询慢,增删快。
  •   HashSet(哈希表): 查询快,增删慢。 (底层其实就是Map) 。 存放的引用类型需重写hashCode()和equals()方法。
  •   LinkedHashSet(哈希链表): 查询慢,增删快。 有序的,存放顺序和取出顺序一致。

1.1,为什么要去重:

  •   在我们开发中,我们所读取的数据难免会有重复数据,我们需要的则是不重复数据的引用,所以需要对数据进行去重,
  •   而基本数据类型的去重比较好去重而引用数据类型呢,因为要判断hashCode运算是否相等,还有equals()是否相等,所以需要去重操作,
  •   我们以一个list集合为例,在该例中,我们将User实体类中姓名和电话号码作为判断该对象重复的标识,在User的实体类中我们重写
  •   这两个方法如下:
 package com.example.pojo;

 public class User {
private String name;
private String region;
private Integer performance;
public User(String name, String region, Integer performance) {
super();
this.name = name;
this.region = region;
this.performance = performance;
}
@Override
public String toString() {
return "User [name=" + name + ", region=" + region + ", performance=" + performance + "]";
}
@Override
public int hashCode() {
final int prime = ;
int result = ;
result = prime * result + ((name == null) ? : name.hashCode());
result = prime * result + ((performance == null) ? : performance.hashCode());
result = prime * result + ((region == null) ? : region.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (performance == null) {
if (other.performance != null)
return false;
} else if (!performance.equals(other.performance))
return false;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
return true;
}
}
  • 以上实体类中,我们在equals()方法中取出该对象的name与region和performance这三个属性值去判断比较,然后在重写的hashCode()
  • 方法中返回这三个属性值得equals对象地址值。

1.2,去重操作步骤:

 package com.example.arraylist;

 import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.example.pojo.User; /**
* @author Administrator
* 思路:
* 1.先对其文本文本进行添加,添加到List<User>中
* 2.把List<User>用迭代器进行迭代
* 3.创建一个新的集合,用来存储不重复的元素
* 4.用while(it.hasNext())有多少元素就循环多少次
* 4.判断新的集合是否有旧的元素如果没有则进行添加
*/
public class ListUserRepeat {
public static void main(String[] args) {
String string="张三,河北,90\n"+
"张三,河南,92\n"+
"李四,湖北,80\n"+
"王五,山西,88\n"+
"张三,河北,90\n"+
"李四,湖北,80\n"+
"马六,山东,77\n";
List<User> list = new ArrayList<>();
String[] split = string.split("\n");
for(String spl : split) {
String[] split2 = spl.split(",");
list.add(new User(split2[], split2[],Integer.parseInt(split2[])));
}
Iterator<User> it = list.iterator();
List<User> listOne = new ArrayList<>();
while(it.hasNext()) {
Object object = it.next();
if(!listOne.contains(object)) {
listOne.add((User) object);
}
}
for (User user : listOne) {
System.out.println(user);
}
}
}

运行这段代码之后,就会很明显的发现,list中重复的用户名,地区,都相同的对象就被会认为是重复的元素而删除掉,很明显运行结果已经达到我们的目的。

二,说一下为什么需要重写equals()方法和hashChode方法():

  • 一般情况下我们重写equals()方法的时候还要重写hashChode()方法,但是我们用的是list所以不用重写hashCode,大家不妨
  • 可以试试上面的例子,在实体类将重写的equals()方法注释掉,再运行程序,这时就会发现运行结果并不是我们刚刚得到的结果,(图中 我用的是list集合,
  • 不是set集合,list集合只需要重写equals()方法就行,而set集合则equals()和hashCode()方法都需要重写)

2.1,String类中的equals()方法的源码如下:

     public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = ;
while (n-- != ) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

通过观察equals()方法的源码我们可以看出,该方法去比较两个对象时,首先先去判断两个对象是否具有相同的地址,如果是同一个对象的引用,则直接放回true;如果地址不一样,则证明不是引用同一个对象,接下来就是挨个去比较两个字符串对象的内容是否一致,完全相等返回true,否则false。

2.2,String类中hashCode()方法的源码如下:

     public int hashCode() {
int h = hash;
if (h == && value.length > ) {
char val[] = value; for (int i = ; i < value.length; i++) {
h = * h + val[i];
}
hash = h;
}
return h;
}

以上是String类中重写的hashCode()方法,在Object类中的hashCode()方法是返回对象的32位JVM内存地址,也就是说如果我们不去重写该方法,将会返回该对象的32位JVM内存地址,以上我们测试的例子中,当注释掉重写的hashCode()方法时,这时默认返回对象的32JVM中的地址,两个不同的对象地址显然是不同的,我们在比较时,虽然通过重写的equals()方法比较出来name和phoneNumber值是相同的,但是默认的hashCode()方法返回的值他们并不是同一个对象,所以我们通常要将hashCode()方法与equals()方法一起重写,以维护hashCode方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

总结:

  用白话说,通过hashCode判断对象是否放在同一个桶里,先确定他们在一个桶里面,然后再通过equals方法去判断这个桶里的对象是不是相同的。

最新文章

  1. React-Native运行知乎日报遇到的问题
  2. git rebase 和 reset的区别
  3. LINQ to Entities 和LINQ to Objects 的区别
  4. iOS仿网易新闻栏目拖动重排添加删除效果
  5. 通信服务器群集——跨服务器通信Demo(源码)
  6. [转]为何TCP/IP协议栈设计成沙漏型的
  7. CentOs6.5中安装和配置vsftp简明教程
  8. 12)Java Constructor
  9. js中定义变量加var与不加var的区别?
  10. 乐视(letv)网tkey破解
  11. jQuery 顶部导航尾随滚动,固定浮动在顶部
  12. spring slf4j log4j maven
  13. C++ 开发OCX 的方法和注意事项
  14. 线程池threadPools
  15. Luogu P2261 [CQOI2007]余数求和
  16. centos 扩容
  17. zepto.js不支持scrollTop的解决办法
  18. Android学习笔记——保存文件(Saving Files)
  19. Linux安装jdk,编写helloworld程序
  20. Java 设计模式系列(二三)访问者模式(Vistor)

热门文章

  1. troubshooting-sqoop 导出 TiDB表数据报com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
  2. Linux查找并杀死僵尸进程(转)
  3. iFrame跨域的方式
  4. okhttp缓存策略源码分析:put&amp;get方法
  5. vue.js中父组件触发子组件中的方法
  6. JDK的收费问题
  7. Aizu - 1383 Pizza Delivery (最短路图+DAG上的割边)
  8. C# 反射 (15)
  9. Load store and memoryless
  10. Visual Studio 查看宏展开