四、Set
1.TreeSet
定义:
可排序的集合;
不能存储空对象;
底层是红黑树;
使用TreeSet 存储对象必须要使用自然排序或者比较器
自然排序
要存储的对象 必须实现了 Comparable 接口,并重写了 compareTo()
在 compareTo() 方法中 制定了比较规则
存储的对象 通过 与 之前的节点对比,返回正数则在 节点的右子树;负数则存储在左子数;返回 0 不存储对象(重复了)
// 实体类实现接口 public class Person implements Comparable<Person> { private int id; private String name; private int age; /** * 重写CompereTo 接口 * 要求: id 从大到小 * id相同,age从小到大 * @param o * @return */ @Override public int compareTo(Person o) { if (this.id == o.getId()){ return this.age-o.getAge() ; } return o.getId() - this.id ; } } // 测试 public class Demo02 { public static void main(String[] args) { TreeSet<Person> people = new TreeSet<>(); people.add(new Person(1,"ls",44)); people.add(new Person(1,"zs",12)); people.add(new Person(8,"t7",14)); people.add(new Person(7,"t7",14)); people.forEach(item -> System.out.println(item)); } }
比较器
在创建TreeSet集合的时候,通过构造方法传递实现了Comparator接口的实现类对象
实现类对象要重写了compare()方法,在方法里面制定排序规则
// 比较器 public class MyCompartor implements Comparator<Person> { /** * id从小到大 * id相同,age从大到小 * @param o1 存储的对象 * @param o2 上一个节点的对象 * @return */ @Override // 11 88 public int compare(Person o1, Person o2) { if (o1.getId() != o2.getId()) return o1.getId()-o2.getId(); return o2.getAge()-o1.getAge(); } } // 测试 public class Demo03 { public static void main(String[] args) { // 通过构造方法传入 比较器 /* TreeSet<Person> people = new TreeSet<>(new MyCompartor()); people.add(new Person(1,"ls",44)); people.add(new Person(1,"zs",12)); people.add(new Person(8,"t7",14)); people.add(new Person(7,"t7",14)); people.forEach(item -> System.out.println(item)); */ // 匿名内部类 TreeSet<Person> people = new TreeSet<>(new Comparator<Person>(){ @Override public int compare(Person o1, Person o2) { if (o1.getId() != o2.getId()) return o1.getId()-o2.getId(); return o2.getAge()-o1.getAge(); } }); people.add(new Person(1,"ls",44)); people.add(new Person(1,"zs",12)); people.add(new Person(8,"t7",14)); people.add(new Person(7,"t7",14)); people.forEach(item -> System.out.println(item)); } }
自然排序 VS 比较器
比较器的优先级别高于自然排序
自然排序需要存储的对象类结构发生改变(实现了 Comparable 接口,并重写compereTo方法)
自然排序的可读性更高,并且排序规则不可见
比较器会创建多一个类
2.HashSet
什么是有序和无序?
- 有序: 根据添加的顺序先后,遍历时以同样的顺序输出
- 无序: 遍历输出 与 添加时的顺序无关(HashSet是无序的)
版本:
JDK1.7 : 底层 hash表(不可变) + 链表
JDK1.8 : 底层 hash表(动态数组) + 链表 + 红黑树
重点:
存储的对象通过hashCode()得到hash值,根据hash值找到在hash表中对应的位置
再根据equals() 判断是否内容相等,内容相等则不存储
当hash表中的对象超过容量的负载因子数时,进行数组扩容,容量为原来的2倍
当一个链表中的对象超过8个,则会转换为红黑树
public class Demo02 { public static void main(String[] args) { HashSet<Integer> hashSet = new HashSet<>(); hashSet.add(12); hashSet.add(11); hashSet.add(22); hashSet.add(22); // lambda表达式 ,打印结果 hashSet.forEach(item -> System.out.println(item)); // 输出:22 11 12 ,说明HashSet是无序的 } }
五、Map
1.HashMap
特点:
无序,key不可重复
简单使用:
key,value都可以为null, key为null的时候存储在HashMap的第一个位置
当key相同时,新的value会覆盖旧的value
public class Demo01 { public static void main(String[] args) { HashMap<String, Integer> map = new HashMap<>(); // 1、添加 map.put("a",13); map.put("b",12); map.put("c",11); map.put("d",678); map.put("a",99); // key重复,后面添加的会覆盖前面的 System.out.println(map); //{a=99, b=12, c=11, d=678} // 2、删除 // 根据key删除 map.remove("a"); // 根据key value 删除 map.remove("c",11); // 3、修改 // 根据key 修改value map.replace("b",88); // 4、打印 System.out.println(map); //{b=88, d=678} // 5、遍历 for不可用 System.out.println("----------- 使用keyset方法转换为保存key值的set集合 ------------"); // 将 map 中的key值存储到 set集合中,set能调用的遍历方法他也能 Set<String> set1 = map.keySet(); Iterator<String> iterator1 = set1.iterator(); while (iterator1.hasNext()){ String key = iterator1.next(); System.out.println("key:"+key +",value:"+map.get(key)); } System.out.println("----------- 使用entrySet方法转换为保存key,value 的Set集合 ------------"); // 将key,value 保存再Map类的内部类 Entry 类中 Set<Map.Entry<String, Integer>> set2 = map.entrySet(); Iterator<Map.Entry<String, Integer>> iterator2 = set2.iterator(); while (iterator2.hasNext()){ Map.Entry<String, Integer> entry = iterator2.next(); System.out.println("key:"+entry.getKey() + ",value:"+entry.getValue()); } } }
2.TreeMap
特点:
底层是红黑树 ,无序 key不可重复
简单使用:
存储映射的关系过程中,需要key使用 自然排序或传递比较器(比较器根据key进行排序)
key不能为null ,value可以为null
添加相同 key 时,新的value会覆盖旧的value(底层:自然排序的compareTo() 或比较器compare()
方法返回值为0,调用t.setValue(value),实现新的值覆盖旧的值)
public class Demo02 { public static void main(String[] args) { System.out.println("--------------TreeMap-----------------"); TreeMap<String, Integer> treeMap = new TreeMap<>(); treeMap.put("a",1); treeMap.put("a",2); // treeMap.put(null,1); treeMap.put("b",null); System.out.println(treeMap); //{a=2, b=null} System.out.println("--------------HashMap-----------------"); HashMap<String, Integer> hashMap = new HashMap<>(); hashMap.put("a",11); hashMap.put(null,11); hashMap.put("b",null); System.out.println(hashMap); //{null=11, a=11, b=null} } }
3.HashTabl
特点:
- 无序,key不可重复
简单使用:
- key,value都不能为空
public class Demo03 { public static void main(String[] args) { Hashtable<String, Integer> hashtable = new Hashtable<>(); hashtable.put("a",1); hashtable.put("c",2); //hashtable.put(null,2); NullPointerException //hashtable.put("d",null); NullPointerException System.out.println(hashtable); } }
六.集合工具类Collections
Java提供了一个操作Set、List和Map等集合的工具类:Collections,该工具类里提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象实现同步控制等方法。
排序操作:排序相关的、顺序相关的功能
reverse():反转指定列表中元素的顺序
shuffle():使用默认随机源对指定列表进行置换(每一次的顺序都不一样)或者打乱顺序 :打乱集合顺序
sort():根据指定比较器产生的顺序对指定列表进行排序(默认从小到大)或者在指定列表的指定位置处交换元素。注意:sort(list)有使用前提:被排序的集合元素必须实现了Comparable接口,重写接口中的compareTo方法定义排序的规则;
swap():交换一下顺序 rotate():根据指定的距离轮换指定列表中的元素
查找和替换操作
max():根据元素的自然顺序,返回给定 collection 的最大元素
min():根据元素的自然顺序,返回给定 collection 的最小元素
replaceAll():使用另一个值替换列表中出现的所有某一指定值 frequency()返回指定 collection中等于指定对象的元素数
binarySearch():使用二分搜索法搜索指定列表,以获得指定对象。
indexOfSubList():查找子列表在列表中第一次出现的位置,没有返回-1
lastIndexOfSubList():查找子列表在列表中最后一次出现的位置,没有返回-1
fill():使用指定元素替换指定列表中的所有元素
同步控制
Collections类中提供了多个synchronized…()方法,这些方法可以将指定集合包装成线程同步(线程安全)的集合,从而可以解决多线程并发访问集合时的线程安全问题。
Java中常用的集合框架中的实现类 ArrayList、Linkedlist、 HashSet、TreeSet、HashMap和TreeMap 都是线程不安全的。如果有多个线程访问它们,而且有超过一个的线程试图修改它们,则存在线程安全的问题。
Collections提供了多个类方法可以把它们包装成线程同步的集合。
代码示例:
public class CollectionsTest { public static void main(String[] args) { ArrayList<Integer> list1 = new ArrayList<>(); list1.add(9); list1.add(2); list1.add(2); Integer[] arr = {7,6,9}; // addAll(Collection<? super T> c, T... elements) 将所有指定的元素添加到指定的集合。 Collections.addAll(list1,4,5,6); Collections.addAll(list1,arr); // 打印集合 System.out.println(list1);//[9, 2, 2, 4, 5, 6, 7, 6, 9] // 对集合元素进行排序 Collections.sort(list1); System.out.println(list1);//[2, 2, 4, 5, 6, 6, 7, 9, 9] } }
后记
Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~