Dog d = new Dog("小黑",5); List得出结果后推导原因: List 接口的特点之一就是可重复 问:如何在ArrayList出完成去除重复值的功能 答: 使用 contains方法进行判断,判断新的集合newLs是否包含指定的元素,如果包含,那么不添加新集合中,如果不包含,那么添加到 新集合中ls=new ArrayList (); ls.add(d); ls.add(d); ls.add(d); System.out.println(ls.size());
public static List写完方法之后再调用之前的案例查看结果 :singleList(List oldLs) { List newLs = new ArrayList ();// 去除重复值之后的集合 for (Dog d : oldLs) {// 遍历需要去除重复值的集合 if (!newLs.contains(d)) {// 如果在新集合中不存在 newLs.add(d);// 加入到新集合中 } } return newLs; }
Dog d = new Dog("小黑",5); List输出结果:ls = new ArrayList (); ls.add(d); ls.add(d); ls.add(d); List newLs = singleList(ls); System.out.println("集合:"+newLs); System.out.println("长度:"+newLs.size());
集合:[Dog [name=小黑, age=5]] 长度:1换种方式在试:
Dog d1 = new Dog("小黑",5); Dog d2 = new Dog("小黑",5); Dog d3 = new Dog("小黑",5); List输出结果 :ls = new ArrayList (); ls.add(d1); ls.add(d2); ls.add(d3); List newLs = singleList(ls); System.out.println("集合:"+newLs); System.out.println("长度:"+newLs.size());
集合:[Dog [name=小黑, age=5], Dog [name=小黑, age=5], Dog [name=小黑, age=5]] 长度:3
- == 与 equals 的区别:
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Dog other = (Dog) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } 重写了equals方法,判断只要名字相同,就认为是同一只狗重新执行上面的代码,输出结果:
集合:[Dog [name=小黑, age=1]] 长度:1讲解原理: contains 方法与 remove 方法的内部都是根据对象的 equals 方法来做判断的 问: 除了这种方式之外,有没有别的方法能够去除重复值? 答: 引入 Set 集合 三:Set接口介绍 Set 接口是继承自 Collection 的子接口,特点:元素不重复
Set输出结果 :set = new HashSet (); set.add("jack");//第一个jack set.add("rose"); set.add("alien"); set.add("jack");//第二个jack for (String s : set) { System.out.println(s); }
rose jack alien四:Set接口下的实现类
- HashSet
- 无序
Setset = new HashSet (); set.add("a"); set.add("d"); set.add("c"); set.add("b"); for (String s : set) { System.out.println(s); }
输出结果:
a b c d要注意强调无序指的是插入的顺序与取出的顺序不一致(从输出结果可以看到) , 原因: 在对象进入 HashSet 内部时 , 会使用对象内部 HashCode 方法计算 hash 值后自动进行排序, 所以读取的是经过内部排序后的数据,所以存入的顺序会与取出的顺序有不同(内部通过排序重 新整理了元素的位置),并且在数据没变的情况下,每次数据输出结果都是一样的顺序
- 不重复
private transient HashMap当我们在调用 add 方法往 HashSet 中添加元素时:map; public HashSet() { map = new HashMap<>(); }
public boolean add(E e) { return map.put(e, PRESENT)==null; } HashMap源码: public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }原理: 在 HashSet 中放入元素的时候 , 相当于将元素放在了一个 Map 哈希表中,在 Map这种哈希表 中,分为键值对形式存储。在上面存入元素时,该元素的 hash 值 hash(key) 会被作为键,而元素 则会被作为值。 HashSet 集合中如何判断两个元素相等的标准: 通过两个对象 hashCode() 方法拿到哈希值,如果两个哈希值相同,再调用 equals() 方法比较 如果都相同,则认定为同一个元素,无法存入 重点: HashSet 保证元素唯一性是靠元素重写 hashCode() 和 equals() 方法来保证的,如果不重写则无法保证
- 代码演示
1.重写hashCode()方法 这个方法的作用就是返回对象的hash值 @Override public int hashCode() { System.out.println("调用了hashCode");//调用时打印 return age;//该对象的hash值就是他的年龄 } @Override public boolean equals(Object obj) { System.out.println("调用了equals");//调用时打印 if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Dog other = (Dog) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true;//只要名字相同 则equals返回真 }
Dog d1 = new Dog("小黑",1); Dog d2 = new Dog("小黑",1); Dog d3 = new Dog("小白",1); HashSetset = new HashSet ();
- 将 d1 添加到集合中
set.add(d1)控制台输出: 调用了 hashCode 原因: 往集合中添加 d1 元素时 , 集合内没有 hash 值为 1 的其他元素 , 所以只调用了 hashCode() 来获取 对象的 hash 值
- 将 d2 添加到集合中
set.add(d2);
- 控制台输出:
- 将 d3 添加到集合中
set.add(d3);调用了 hashCode 调用了 equals 问:此处的集合长度? set 集合的长度 :2 原因讲解: hash 值虽然相同,但是 equals 时得到的结果不对应,所以不被认为是相同的元素,所以添加成 功 注意: 判断元素是否存在,以及删除等操作,用作判断的条件同样是 hashCode()+equals() 方法 五:TreeSet TreeSet 是一个有序的集合,它的作用是提供有序的 Set 集合(没有重复值)
- 有序
TreeSet输出结果:set=new TreeSet (); set.add("jack"); set.add("rose"); set.add("alien"); for (String s : set) { System.out.println(s); }
alien jack rose
- 排序方式:自然排序
@Override public int compareTo(Object o) { // TODO Auto-generated method stub return 0; }返回值:
将代码修改为按照年龄排序:
- 如果返回值>0,他大
- 如果返回值=0,相等
- 如果返回值<0,我大
@Override public int compareTo(Object o) { // TODO Auto-generated method stub return this.age-((Dog)o).getAge(); }代码:
Dog d1 = new Dog("小黑", 23); Dog d2 = new Dog("小白", 35); Dog d3 = new Dog("小青", 18); Dog d4 = new Dog("小绿", 22); TreeSet输出结果:ts = new TreeSet (); ts.add(d1); ts.add(d2); ts.add(d3); ts.add(d4); for (Dog d : ts) { System.out.println(d); }
Dog [name=小青, age=18] Dog [name=小绿, age=22] Dog [name=小黑, age=23] Dog [name=小白, age=35]如果年龄相同,则可以按照其他条件来排序,比如:名字
@Override public int compareTo(Object o) { // TODO Auto-generated method stub Dog d=(Dog)o; int num=this.age-d.getAge(); if(num==0) { return this.name.compareTo(d.getName()); } return num; }
- 比较器排序
public class DogComparator implements Comparator重写compare方法:{ }
@Override public int compare(Dog o1, Dog o2) { return 0; } 按照年龄排序 @Override public int compare(Dog o1, Dog o2) { return o1.getAge()-o2.getAge(); } 在年龄相同的时候(主条件),可以根据名字来排序(次条件) @Override public int compare(Dog o1, Dog o2) { int x=o1.getAge()-o2.getAge(); if(x==0) return o1.getName().compareTo(o2.getName()); return x; }
在初始化TreeSet的时候将我们写好的比较器传入就可以了(提醒要注意):
Dog d1 = new Dog("小黑", 23); Dog d2 = new Dog("小白", 35); Dog d3 = new Dog("小青", 18); Dog d4 = new Dog("小绿", 22); TreeSet输出结果:ts = new TreeSet (new DogComparator());//指定比较器 ts.add(d1); ts.add(d2); ts.add(d3); ts.add(d4); for (Dog d : ts) { System.out.println(d); }
Dog [name=小青, age=18] Dog [name=小绿, age=22] Dog [name=小黑, age=23] Dog [name=小白, age=35]问:如何将集合中的排列改成从大到小?
比较优先级:比较器排序大于自然排序
- 二叉树
- 为什么会需要泛型
List ls=new ArrayList(); ls.add(1); ls.add("a"); for (Object o : ls) { System.out.println((Integer)o); }如果集合对于元素类型没有限制,对于取数据的人来说,还需要先转为对应的类型再来操作,并且可能会报异常 引出泛型的作用,在编译时期就限制数据类型
package com.zking.collection01.util; import java.util.List; import java.util.ListIterator; import java.util.ArrayList; import java.util.Iterator; public class Demo2 { public static void main(String[] args) { //泛型:以类型作为参数的类就叫泛型 //作用:提供程序的健壮性、简化代码 //泛型的默认类型为Object //泛型是从jdk1.5之后推出的 List七:提问lst=new ArrayList<>(); //lst.add("zs"); lst.add(1); lst.add(2); lst.add(7); lst.add(6); //获取迭代器 ListIterator it = lst.listIterator(); //循环遍历 while(it.hasNext()) { //获取集合中的元素(先移动下标) //Object val = it.next(); //转换数据类型 //int num=Integer.parseInt(val.toString()); Integer num = it.next(); //获取偶数数据 if(num%2==0) System.out.println(num); } //装箱 int a=1; Integer num=new Integer(a); //拆箱 int b = num.intValue(); } }
- 如何去除ArrayList中的重复值?
- 编写代码
- List与Set的转换
- HashSet与TreeSet的区别?
- 底层数据结构
- 顺序
- TreeSet是有序的吗?
- 插入顺序
- 数据顺序
- TreeSet在排序时如何比较元素?
- 自然排序
- 选择器排序
- HashSet如何检查重复?
- hashCode()+equals()