关于List、Set、Map接口讲解
概述
List、Set接口都是继承于Collection主接口,而Map为独立接口
2、Set接口下有HashSet、LinkedHashSet、TreeSet实现类
特点
Collection接口:
——List接口 有序,可重复
ArrayList
优点: 底层数据结构是数组,查询快,增删慢
缺点: 线程不安全,效率高
LinkedList
优点: 底层数据结构是链表,查询慢,增删快
缺点: 线程不安全,效率高
Vector
优点: 底层数据结构是数组,查询快,增删慢
缺点: 线程安全,效率低
——Set 无序,唯一
HashSet
底层数据结构是哈希表。(无序,唯一)
如何来保证元素唯一性?
答:依赖两个方法:hashCode()和equals()
LinkedHashSet
底层数据结构是链表和哈希表 (FIFO插入有序,且唯一)
原因如下两点:
答:1.由链表保证元素有序
2.由哈希表保证元素唯一
TreeSet
底层数据结构是红黑树。(唯一,且有序)
1. 如何保证元素排序的呢?
答:1.自然排序
2.比较器排序
2.如何保证元素唯一性的呢?
答:根据比较的返回值是否是0来决定
针对于Collection集合我们到底如何使用呢?(重点掌握)
唯一吗?
是:Set
排序吗?
是:TreeSet或LinkedHashSet
否:HashSet
如果你知道是Set,但是不知道是哪个Set,就用HashSet。
--------------------------------------------------------------------------------------
否:List
要安全吗?
是:Vector
否:ArrayList或者LinkedList
查询多:ArrayList
增删多:LinkedList
如果你知道是List,但是不知道是哪个List,就用ArrayList。如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。
Map接口:
Map接口有三个重要的实现类,分别是 HashMap、LinkedHashMap、Hashtable
1、TreeMap是有序的,HashMap和Hashtable是无序的。
2、Hashtable的方法是同步的,底层源码方法有(synchronized)这是两者主要区别。
这就意味着:
3、Hashtable是线程安全,HashMap是非线程安全。
4、HashMap效率较高,Hashtable效率较低.
重点问题重点分析
(一)、TreeSet,LinkedHashSet and HashSet 的区别
1.介绍
TreeSet,LinkedHashSet and HashSet 在Java中都是实现Set的数据结构
1.TreeSet的主要功能用于排序
2.LinkedHashSet的主要功能用于保证FIFO即有序的集合(先进先出)
3.HashSet只是通用的存储数据的集合
2.相同点
重复元素:因为三者都实现Set interface,所以三者都不包含重复元素.
线程安全:三者都不是线程安全的,如果要使用线程安全可以Collections.synchronizedSet()
3.不同点
性能和速度:HashSet插入数据最快,其次LinkHashSet,最慢的是TreeSet因为内部实现排序。
排序:HashSet不保证有序,LinkHashSet保证FIFO即按插入顺序排序,TreeSet安装内部实现排序,也可以自定义排序规则。
Null:HashSet和LinkHashSet允许存在null数据,但是TreeSet中插入null数据时会报NullPointerException异常。
4.不多说了上代码进行比较!
package com.jia.set; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.TreeSet; public class SetDemo { public static void main(String args[]) { HashSet<String> hashSet = new HashSet<>(); LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>(); TreeSet<String> treeSet = new TreeSet<>(); for (String data : Arrays.asList("B", "A", "D", "C", "E")) { hashSet.add(data); linkedHashSet.add(data); treeSet.add(data); } // 不保证有序 System.out.println("HashSet排序 :" + hashSet); // FIFO保证安装插入顺序排序 System.out.println("LinkedHashSet插入顺序排序 :" + linkedHashSet); // 内部实现排序 System.out.println("TreeSet内部排序 :" + treeSet); } }
运行结果:
HashSet排序 :[A, B, C, D, E]
LinkedHashSet插入顺序排序 :[B, A, D, C, E]
TreeSet内部排序 :[A, B, C, D, E]
(二)、TreeSet的两种排序方式比较
1.排序的引入 (以基本数据类型的排序为例)
package com.jia.set; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { // 创建集合对象 // 自然顺序进行排序 TreeSet<Integer> treeSet = new TreeSet<Integer>(); // 创建元素并添加 // 3,6,9,12,15,18,21,22,30 treeSet.add(3); treeSet.add(6); treeSet.add(9); treeSet.add(12); treeSet.add(15); treeSet.add(18); treeSet.add(21); treeSet.add(22); treeSet.add(30); // 遍历结果 for (Integer data : treeSet) { System.out.println("TreeSet --> "+data); } } }
运行结果:
TreeSet --> 3 TreeSet --> 6 TreeSet --> 9 TreeSet --> 12 TreeSet --> 15 TreeSet --> 18 TreeSet --> 21 TreeSet --> 22 TreeSet --> 30
2.如果是引用数据类型来说,比如自定义对象,又该如何排序呢?
比如创建一个学生类:
package com.jia.set; //学生类 public class Student { private Integer id; private String name; public Student() { } public Student(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
测试类:
package com.jia.set; import java.util.TreeSet; public class StudentTreeSetDemo { public static void main(String[] args) { TreeSet<Student> treeSet = new TreeSet<Student>(); //创建元素对象 Student s1=new Student(1,"张三"); Student s2=new Student(2,"李四"); Student s3=new Student(3,"王五"); Student s4=new Student(4,"赵六"); Student s5=new Student(5,"陈七"); Student s6=new Student(6,"杨八"); //将元素对象添加到集合对象中 treeSet.add(s1); treeSet.add(s2); treeSet.add(s3); treeSet.add(s4); treeSet.add(s5); treeSet.add(s6); //遍历结果 for (Student student : treeSet) { System.out.println(student.getId()+"--->"+student.getName()); } } }
结果报错:
Exception in thread "main" java.lang.ClassCastException: com.jia.set.Student cannot be cast to java.lang.Comparable at java.util.TreeMap.compare(TreeMap.java:1294) at java.util.TreeMap.put(TreeMap.java:538) at java.util.TreeSet.add(TreeSet.java:255) at com.jia.set.StudentTreeSetDemo.main(StudentTreeSetDemo.java:20)
原因分析:
由于不知道该安照那一中排序方式排序,所以会报错。
解决方法:
1.自然排序
2.比较器排序
(1)自然排序
自然排序要进行一下操作:
1.Student类中实现Comparable接口
2.重写Comparable接口中的Comparable()方法
public int compareTo(T o); 比较此对象与指定对象的顺序。
package com.jia.set; //学生类 public class Student implements Comparable<Student> { private Integer id; private String name; public Student() { } public Student(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + '}'; } @Override public int compareTo(Student s) { //return -1; //-1表示放在红黑树的左边,即逆序输出 //return 1; //1表示放在红黑树的右边,即顺序输出 //return o; //表示元素相同,仅存放第一个元素 //主要条件 姓名的长度,如果姓名长度小的就放在左子树,否则放在右子树 int num = this.name.length()-s.name.length(); //姓名的长度相同,不代表内容相同,如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数。 //如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。 //如果这两个字符串相等,则结果为 0 int num1 = num==0?this.name.compareTo(s.name):num; //姓名的长度和内容相同,不代表id值相同,所以还要判断id int num2=num1==0?this.id-s.id:num1; return num2; } }
运行结果:
1--->张三 2--->李四 6--->杨八 3--->王五 4--->赵六 5--->陈七
(2)比较器排序
步骤:1.单独创建一个比较类,以ComparatorTest为例,并且让其继承Comparator接口
2.重写Comparable接口中的Comparable()方法
compare(T o1,T o2) 比较用来排序的两个参数。
TreeSet(Comparator<? superE> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
创建比较类ComparatorTest:
package com.jia.set; import java.util.Comparator; public class ComparatorTest implements Comparator<Student> { @Override public int compare(Student s1,Student s2) { // 姓名长度 int num = s1.getName().length() - s2.getName().length(); // 姓名内容 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num; // id值 int num3 = num2 == 0 ? s1.getId() - s2.getId() : num2; return num3; } }
学生类:
package com.jia.set; //学生类 public class Student { private Integer id; private String name; public Student() { super(); } public Student(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
测试类:
package com.jia.set; import java.util.TreeSet; public class StudentTreeSetDemo { public static void main(String[] args) { TreeSet<Student> treeSet = new TreeSet<Student>(new ComparatorTest()); //创建元素对象 Student s1=new Student(1,"张三"); Student s2=new Student(2,"李四"); Student s3=new Student(3,"王五"); Student s4=new Student(4,"赵六"); Student s5=new Student(5,"陈七"); Student s6=new Student(6,"杨八"); //将元素对象添加到集合对象中 treeSet.add(s1); treeSet.add(s2); treeSet.add(s3); treeSet.add(s4); treeSet.add(s5); treeSet.add(s6); //遍历结果 for (Student student : treeSet) { System.out.println(student.getId()+"--->"+student.getName()); } } }
运行结果:
1--->张三 2--->李四 6--->杨八 3--->王五 4--->赵六 5--->陈七
性能就不多讲了:HashSet > LinkedHashSet > TreeSet