概述:

  • List , Set, Map都是接口;List , Set继承至Collection接口,Map为独立接口
  • Set下有HashSet,LinkedHashSet,TreeSet
  • List下有ArrayList,Vector,LinkedList
  • Map下有Hashtable,LinkedHashMap,HashMap,TreeMap
  • Collection接口下还有个Queue接口,有PriorityQueue类

注意:

  • Queue接口与List、Set同一级别,都是继承了Collection接口。
  • 看图你会发现,LinkedList既可以实现Queue接口,也可以实现List接口.只不过呢, LinkedList实现了Queue接口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。
  • SortedSet是个接口,它里面的(只有TreeSet这一个实现可用)中的元素一定是有序的。

总结:

Connection接口:

— List 有序,可重复

    • ArrayList
      优点: 底层数据结构是数组,查询快,增删慢。
      缺点: 线程不安全,效率高
    • Vector
      优点: 底层数据结构是数组,查询快,增删慢。
      缺点: 线程安全,效率低
    • LinkedList
      优点: 底层数据结构是链表,查询慢,增删快。
      缺点: 线程不安全,效率高

—Set 无序,唯一

    HashSet
    底层数据结构是哈希表。(无序,唯一)
    如何来保证元素唯一性?
    1.依赖两个方法:hashCode()和equals()

    LinkedHashSet
    底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
    1.由链表保证元素有序
    2.由哈希表保证元素唯一

    TreeSet
    底层数据结构是红黑树。(唯一,有序)
    1. 如何保证元素排序的呢?
    自然排序
    比较器排序
    2.如何保证元素唯一性的呢?
    根据比较的返回值是否是0来决定

针对Collection集合我们到底使用谁呢?(掌握)

唯一吗?

  是:Set

    排序吗?

      是:TreeSet或LinkedHashSet
      否:HashSet

      如果你知道是Set,但是不知道是哪个Set,就用HashSet。
  否:List

    要安全吗?

      是:Vector
      否:ArrayList或者LinkedList       查询多:ArrayList
      增删多:LinkedList
      如果你知道是List,但是不知道是哪个List,就用ArrayList。
如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。
如果你知道用集合,就用ArrayList。

说完了Collection,来简单说一下Map.

Map接口:

Map接口有三个比较重要的实现类,分别是HashMap、TreeMap和HashTable。

  • TreeMap是有序的,HashMap和HashTable是无序的。
  • Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。

这就意味着:

  • Hashtable是线程安全的,HashMap不是线程安全的。
  • HashMap效率较高,Hashtable效率较低。如果对同步性或与遗留代码的兼容性没有任何要求,建议使用HashMap。 查看Hashtable的源代码就可以发现,除构造函数外,Hashtable的所有 public 方法声明中都有 synchronized关键字,而HashMap的源码中则没有。
  • Hashtable不允许null值,HashMap允许null值(key和value都允许)
  • 父类不同:Hashtable的父类是Dictionary,HashMap的父类是AbstractMap

重点问题重点分析:

(一).TreeSet, LinkedHashSet and HashSet 的区别

1. 介绍
TreeSet, LinkedHashSet and HashSet 在java中都是实现Set的数据结构
  • TreeSet的主要功能用于排序
  • LinkedHashSet的主要功能用于保证FIFO即有序的集合(先进先出)
  • HashSet只是通用的存储数据的集合
2. 相同点
  • Duplicates elements: 因为三者都实现Set interface,所以三者都不包含duplicate elements
  • Thread safety: 三者都不是线程安全的,如果要使用线程安全可以Collections.synchronizedSet()
3. 不同点
  • Performance and Speed: HashSet插入数据最快,其次LinkHashSet,最慢的是TreeSet因为内部实现排序
  • Ordering: HashSet不保证有序,LinkHashSet保证FIFO即按插入顺序排序,TreeSet安装内部实现排序,也可以自定义排序规则
  • null:HashSet和LinkHashSet允许存在null数据,但是TreeSet中插入null数据时会报NullPointerException
4. 代码比较
  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", "E", "D", "C", "A")) {
hashSet.add(data);
linkedHashSet.add(data);
treeSet.add(data);
} //不保证有序
System.out.println("Ordering in HashSet :" + hashSet); //FIFO保证安装插入顺序排序
System.out.println("Order of element in LinkedHashSet :" + linkedHashSet); //内部实现排序
System.out.println("Order of objects in TreeSet :" + treeSet);
}

运行结果:
Ordering in HashSet :[A, B, C, D, E] (无顺序)
Order of element in LinkedHashSet :[B, E, D, C, A] (FIFO插入有序)
Order of objects in TreeSet :[A, B, C, D, E] (排序)

(二).TreeSet的两种排序方式比

1.排序的引入(以基本数据类型的排序为例)

由于TreeSet可以实现对元素按照某种规则进行排序,例如下面的例子

public class MyClass {

    public static void main(String[] args) {
// 创建集合对象
// 自然顺序进行排序
TreeSet<Integer> ts = new TreeSet<Integer>(); // 创建元素并添加
// 20,18,23,22,17,24,19,18,24
ts.add();
ts.add();
ts.add();
ts.add();
ts.add();
ts.add();
ts.add();
ts.add();
ts.add(); // 遍历
for (Integer i : ts) {
System.out.println(i);
}
}
}
运行结果:
17
18
19
20
22
23
24
2.如果是引用数据类型呢,比如自定义对象,又该如何排序呢?

测试类:

public class MyClass {
public static void main(String[] args) {
TreeSet<Student> ts=new TreeSet<Student>();
//创建元素对象
Student s1=new Student("zhangsan",);
Student s2=new Student("lis",);
Student s3=new Student("wangwu",);
Student s4=new Student("chenliu",);
Student s5=new Student("zhangsan",);
Student s6=new Student("qianqi",); //将元素对象添加到集合对象中
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6); //遍历
for(Student s:ts){
System.out.println(s.getName()+"-----------"+s.getAge());
}
}
}

Student.java:

public class Student {
private String name;
private int age; public Student() {
super();
// TODO Auto-generated constructor stub
} public Student(String name, int age) {
super();
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
}

结果报错:

原因分析:
由于不知道该安照那一中排序方式排序,所以会报错。
解决方法:
1.自然排序
2.比较器排序

(1).自然排序

自然排序要进行一下操作:
1.Student类中实现 Comparable接口
2.重写Comparable接口中的Compareto方法

compareTo(To) 比较此对象与指定对象的顺序。

public class Student implements Comparable<Student>{
private String name;
private int age; public Student() {
super();
// TODO Auto-generated constructor stub
} public Student(String name, int age) {
super();
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @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==?this.name.compareTo(s.name):num;
//姓名的长度和内容相同,不代表年龄相同,所以还要判断年龄
int num2=num1==?this.age-s.age:num1;
return num2;
}
} 运行结果:
lis-----------22
qianqi-----------24
wangwu-----------24
chenliu-----------26
zhangsan-----------20
zhangsan-----------22
(2).比较器排序

比较器排序步骤:
1.单独创建一个比较类,这里以MyComparator为例,并且要让其继承Comparator接口
2.重写Comparator接口中的Compare方法

compare(T o1,T o2) 比较用来排序的两个参数。

3.在主类中使用下面的 构造方法

TreeSet(Comparator<? superE> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。

测试类:

public class MyClass {

    public static void main(String[] args) {
//创建集合对象
//TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
TreeSet<Student> ts=new TreeSet<Student>(new MyComparator()); //创建元素对象
Student s1=new Student("zhangsan",);
Student s2=new Student("lis",);
Student s3=new Student("wangwu",);
Student s4=new Student("chenliu",);
Student s5=new Student("zhangsan",);
Student s6=new Student("qianqi",); //将元素对象添加到集合对象中
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6); //遍历
for(Student s:ts){
System.out.println(s.getName()+"-----------"+s.getAge());
}
}
}

Student.java:

public class Student {
private String name;
private int age; public Student() {
super();
// TODO Auto-generated constructor stub
} public Student(String name, int age) {
super();
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} }

MyComparator类:

public class MyComparator implements Comparator<Student> {

    @Override
public int compare(Student s1,Student s2) {
// 姓名长度
int num = s1.getName().length() - s2.getName().length();
// 姓名内容
int num2 = num == ? s1.getName().compareTo(s2.getName()) : num;
// 年龄
int num3 = num2 == ? s1.getAge() - s2.getAge() : num2;
return num3;
} }
运行结果:
lis-----------22
qianqi-----------24
wangwu-----------24
chenliu-----------26
zhangsan-----------20
zhangsan-----------22

(三). 性能测试

对象类: 

class Dog implements Comparable<Dog> {
int size;
public Dog(int s) {
size = s;
}
public String toString() {
return size + "";
}
@Override
public int compareTo(Dog o) {
//数值大小比较
return size - o.size;
}
}

主类:

public class MyClass {

    public static void main(String[] args) {

        Random r = new Random();
HashSet<Dog> hashSet = new HashSet<Dog>();
TreeSet<Dog> treeSet = new TreeSet<Dog>();
LinkedHashSet<Dog> linkedSet = new LinkedHashSet<Dog>(); // start time
long startTime = System.nanoTime();
for (int i = ; i < ; i++) {
int x = r.nextInt( - ) + ;
hashSet.add(new Dog(x));
} // end time
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("HashSet: " + duration); // start time
startTime = System.nanoTime();
for (int i = ; i < ; i++) {
int x = r.nextInt( - ) + ;
treeSet.add(new Dog(x));
}
// end time
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("TreeSet: " + duration); // start time
startTime = System.nanoTime();
for (int i = ; i < ; i++) {
int x = r.nextInt( - ) + ;
linkedSet.add(new Dog(x));
} // end time
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("LinkedHashSet: " + duration);
} }
运行结果: HashSet: 1544313
TreeSet: 2066049
LinkedHashSet: 629826
虽然测试不够准确,但能反映得出,TreeSet要慢得多,因为它是有序的。

转载请注明出处:Java集合中List,Set以及Map等集合体系详解

												

Java集合中List、Set以及Map的更多相关文章

  1. Java集合中List,Set以及Map等集合体系详解

    转载请注明出处:Java集合中List,Set以及Map等集合体系详解(史上最全) 概述: List , Set, Map都是接口,前两个继承至collection接口,Map为独立接口 Set下有H ...

  2. 史上最全Java集合中List,Set以及Map等集合体系详解

    一.概述 List , Set, Map都是接口,前两个继承至collection接口,Map为独立接口 Set下有HashSet,LinkedHashSet,TreeSet List下有ArrayL ...

  3. Java集合中List,Set以及Map等集合体系详解(史上最全)

    https://blog.csdn.net/zhangqunshuai/article/details/80660974

  4. Java集合中的LinkedHashMap类

    jdk1.8.0_144 本文阅读最好先了解HashMap底层,可前往<Java集合中的HashMap类>. LinkedHashMap由于它的插入有序特性,也是一种比较常用的Map集合. ...

  5. Java集合(十)实现Map接口的HashMap

    Java集合(十)继承Map接口的HashMap 一.HashMap简介(基于JDK1.8) HashMap是基于哈希表(散列表),实现Map接口的双列集合,数据结构是“链表散列”,也就是数组+链表 ...

  6. java集合中List与set的区别

       java集合中List与set的区别.     List可以存储元素为有序性并且元素可以相同.     set存储元素为无序性并且元素不可以相同.     下面贴几段代码感受一下: ArrayL ...

  7. Java集合中Comparator和Comparable接口的使用

    在Java集合中,如果要比较引用类型泛型的List,我们使用Comparator和Comparable两个接口. Comparable接口 -- 默认比较规则,可比较的 实现该接口表示:这个类的实例可 ...

  8. Java集合中Set的常见问题及用法

    在这里演示的案例是衔接Java集合中的List(点击查看)那篇博文的,本节我们学习的Set的用法. Set是Collection的一个重要的子接口,Set中的元素是无序排列的,并且元素不可以重复,被称 ...

  9. Java集合中迭代器的常用用法

    该例子展示了一个Java集合中迭代器的常用用法public class LinkedListTest { public static void main(String[] args) { List&l ...

随机推荐

  1. jdk8与jdk7中hashMap的resize分析

    在分析代码之前,我们先抛出下面的问题: hashmap 扩容时每个 entry 需要再计算一次 hash 吗? 我们首先看看jdk7中的hashmap的resize实现 1 void resize(i ...

  2. MySQL-5.7.21非图形化下载、安装、连接问题记录

    1.安装包下载链接:https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.21-winx64.zip 官网:https://www.mysql.co ...

  3. JDK容器类List,Set,Queue源码解读

    List,Set,Queue都是继承Collection接口的单列集合接口.List常用的实现主要有ArrayList,LinkedList,List中的数据是有序可重复的.Set常用的实现主要是Ha ...

  4. 开发一个Spring Boot Starter!

    在上一篇文章中,我们已经了解了一个starter实现自动配置的基本流程,在这一小结我们将复现上一过程,实现一个自定义的starter. 先来分析starter的需求: 在项目中添加自定义的starte ...

  5. React Native 混合开发与实现

    关于 微信公众号:前端呼啦圈(Love-FED) 我的博客:劳卜的博客 知乎专栏:前端呼啦圈 前言 随着 React 的盛行,其移动开发框架 React Native 也收到了广大开发者的青睐,以下简 ...

  6. 【Spring Boot】利用 Spring Boot Admin 进行项目监控管理

    利用 Spring Boot Admin 进行项目监控管理 一.Spring Boot Admin 是什么 Spring Boot Admin (SBA) 是一个社区开源项目,用于管理和监视 Spri ...

  7. 【记录】SpringBoot 2.X整合Log4j没有输出INFO、DEBUG等日志信息解决方案

    由于批量更新的时候一直无法定位问题出处,就去服务器定位日志,奈何日志一直无法输出,为了能够更好的定位问题,痛定思痛后逐步排查最终解决问题.如有客官看到此处,请不要盲目对号入座,我的项目环境或许与你有区 ...

  8. idea设置docker远程插件

    简介 docker都是通过命令来操作容器,使用idea插件可以减少重复命令输入等. 使用步骤 Idea内安装插件 打开Idea,Preferences | Plugins 进入插件安装界面,在搜索框中 ...

  9. 一文了解:Redis主从复制

    Redis主从复制 主从复制 主从复制,将一台Redis服务器的数据,复制到其他Redis服务器.前者称为主(master)节点,后者称为从(slave)节点 . 在默认的情况下,Redis都是主节点 ...

  10. Python-demo(photo)

    import osimport urllib import requests#import wximport time from fake_useragent import UserAgentfrom ...