011集合(java基础)

目录

一、集合框架图

二、Set

1、HashSet

2、LinkedHashSet

3、TreeSet

三、List

 1、ArrayList

2、LinkedList

3、Vector

四、Map

1、HashMap

(1)put()的实现原理

(2)get()的实现原理

(3)红黑树

2、LinkedHashMap(有序)

3、HashTable(线程安全&键值都不能null)

4、TreeMap(有序)

5、ConcurrentHashMap

五、总结

1、是否可重复

2、是否允许null

3、是否线程安全

4、是否有序


一、集合框架图

主要要了解三大种集合,Set、List、Map

二、Set

Set集合通常不能记住元素的添加顺序。实际上Set就是Collection只是行为略有不同(Set不允许包含重复元素)

1、HashSet

(1)底层实现(数组+链表+红黑树)

HashSet 的内部采用了HashMap作为数据存储,HashSet其实就是在操作HashMap的key,

而HashMap是采用哈希表存储数据的,哈希表的结构,jdk1.8之后,就是数组+链表+红黑树

(2)是否有序(无序)

因为HashMap是无序的,因此HashSet也不能保证元素的顺序

(3)是否唯一(唯一)

因为无序,所以唯一

(4)是否线程安全(不安全)

因为HashSet中没有对应同步的操作,因此是线程不安全的

(5)是否支持null(允许有一个null)

支持null元素(因为hashMap也支持null键和null值)

(6)遍历方式(迭代器、增强for循环)

两种遍历方式

  • 迭代器
  • 增强for循环
public static void main(String[] args){
		
		Set<String> set = new HashSet<String>();
		set.add("a1");
		set.add("b2");
		set.add("c3");
		set.add("d4");
		
		// 初始化一个HashSet集合
		System.out.println("--------原HashSet集合----------");
		System.out.println(set);
		System.out.println();
		
		// 方法一:
		Iterator<String> iterator = set.iterator();
		System.out.println("--------迭代器遍历HashSet----------");
		while(iterator.hasNext()){
			System.out.print(iterator.next()+",");
		}
		
		
		// 方法二:
		System.out.println("--------加强for循环遍历---------");
		for (String item : set) {
			System.out.print(item+",");
		}
}

2、LinkedHashSet

(1)底层实现(数组+双向链表+红黑树)

LinkedHashSet基于LinkedHashMap开发的,其构造函数中调用父类的构造函数,而在它的父类的这个有参构造函数中,new了个LinkedHashMap

这个super就是调用父类构造函数,点进去发现:

 (2)是否有序(有序)

在添加一个元素时,先求 hash 值,在求索引,确定该元素在hashtable的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加,和 hashset 一样)

(3)是否唯一(唯一)

唯一

(4)是否线程安全(不安全)

也没有对应同步的操作,因此是线程不安全的

(5)是否支持null(允许有一个null)

支持null元素(因为hashMap也支持null键和null值)

(6)遍历方式(迭代器、增强for循环)

跟HashSet遍历方式一样

3、TreeSet

(1)底层实现(数组+双向链表+红黑树)

TreeSet 底层实际使用的存储容器就是 TreeMap,底层是红黑树,查找和增删效率高

(2)是否有序(有序)

需要实现Comparable接口,并重写compareTo()方法,然后放入TreeSet中的数据会按照一定规则排序

(3)是否唯一(唯一)

(4)是否线程安全(不安全)

(5)是否支持null(不支持null值!!!)

 TreeSet中不能放入null元素

(6)遍历方式(迭代器、增强for循环)

(7) 如果要放入TreeSet中的类没有实现Comparable接口重写compareTo(),则会抛出异常

三、List

 1、ArrayList

(1)底层实现(数组)

所以查找快,增删慢,因为增删的时候可能涉及到要移动后续的所有数据

(2)是否有序(有序)

按照存放的顺序排序

(3)是否唯一(不唯一)

(4)是否线程安全(不安全)

非常适合用于对元素进行查找,效率非常高

(5)是否支持null(支持,而且可以存放多个null)

(6)遍历方式(迭代器、增强for循环、普通for循环)

  • 普通for循环:根据下标,从0,遍历到list.size()-1,通过list的get(下标)方法
  • 增强for循环
  • iterator迭代器:
public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("bbba");
		list.add(null);
		list.add("bbbb");
		list.add("aaaa");
		list.add(null);

		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}

		System.out.println("--------------------");
		for (String s : list) {
			System.out.println(s);
		}

		System.out.println("--------------------");

		Iterator<String> it = list.iterator();
		while (it.hasNext()) {
            System.out.println(it.next());
		}
	}

(7)初始容量和扩容(ArrayList底层数组每次扩容的大小都是1.5倍)

初始0,放入一个元素时是扩容到10,之后都是增加为之前的1.5倍(向下取整)

2、LinkedList

(1)底层实现(双向链表

(2)是否有序(有序)

按照存放的顺序排序

(3)是否唯一(不唯一)

(4)是否线程安全(不安全)

(5)是否支持null(支持,而且可以存放多个null)

(6)遍历方式(迭代器、增强for循环、普通for循环)

3、Vector

(1)底层实现(数组

(2)是否有序(有序)

按照存放的顺序排序

(3)是否唯一(不唯一)

(4)是否线程安全(安全)

(5)是否支持null(支持,而且可以存放多个null)

(6)遍历方式(迭代器、增强for循环、普通for循环)

(7)初始容量和扩容(ArrayList底层数组每次扩容的大小都是2倍)

初始0,放入一个元素时是扩容到10,之后都是增加为之前的2倍

四、Map

1、HashMap

HashMap非常重要!!!所以要写得详细一点

(1)put()的实现原理

  • 首先将k,v封装到Node对象当中(节点)
  • 然后它的底层会调用K的hashCode()方法得出hash值
  • 通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖

(2)get()的实现原理

  • 先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
  • 通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。

(3)红黑树

jdk1.8最重要的就是引入了红黑树的设计

当hash表的长度超过了8,链表结构就会转成红黑树,好处就是避免在最极端的情况下链表变得很长很长,在查询的时候,效率会非常慢

  • 红黑树查询:其访问性能近似于折半查找,时间复杂度 O(logn);
  • 链表查询:这种情况下,需要遍历全部元素才行,时间复杂度 O(n);

 对于红黑二叉树而言,主要包括三大基本操作:左旋、右旋、着色。很复杂,感兴趣的可以专门找有关的书或者文章看看)

(4)底层实现(数组+链表+红黑树

(5)是否唯一(key唯一,value随便)

如果两次put的key是相同的,后面的会覆盖前面的value

(6)是否线程安全(不安全)

(7)是否支持null(支持一个值为null的key)

value随便null不null

(8)初始容量与扩容(初始16,扩容*2)

(9)遍历方式(迭代器、foreach、Lambda、Stream API)

【迭代器(entrySet()或keySet()点iterator),foreach(keySet()或entrySet()),Lambda,Stream API(stream()或parallelStream())】

遍历方式1:entrySet+迭代器+while,然后用next().getKey()和next().getValue()依次获取键和值

遍历方式2:entrySet+foreach,Set集合每一个元素是Node(Node节点中有Key和value),循环获取每个节点node,然后通过node.getKey()和node.getValue()来获取键值

遍历方式3:keySet+迭代器+while,.next()获取所有key,map.get(key)获取对应的value

遍历方式4:keySet+foreach

遍历方式6:Stream API单线程,stream()

遍历方式7:Stream API多线程,parallelStream()

public static void main(String[] args) {
		HashMap<String, String> map = new HashMap<String, String>();
		map.put("bb", "值1");
		map.put(null, "值null1");
		map.put("aa", "值2");
		map.put("aa", "值3");
		map.put(null, "值null2");
		map.put("cc", "值4");
		map.put("cc", null);

		System.out.println("===========遍历方式1:entrySet迭代器===========");
		Iterator<Entry<String, String>> iterator = map.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry<String, String> next = iterator.next();
			System.out.println(next.getKey() + ":" + next.getValue());
		}
		System.out.println("===========遍历方式2:entrySet节点(一个节点包含一对键值)===========");
		Set<Entry<String, String>> nodes = map.entrySet();
		for (Entry<String, String> node : nodes) {
			System.out.println(node.getKey() + ":" + node.getValue());
		}
		System.out.println("===========遍历方式3:KeySet迭代器===========");
		Iterator<String> iterator2 = map.keySet().iterator();
		while (iterator2.hasNext()) {
			String key = iterator2.next();
			System.out.println(key + ":" + map.get(key));
		}

		System.out.println("===========遍历方式4:keySet获取所有key===========");
		Set<String> keySet = map.keySet();
		for (String key : keySet) {
			System.out.println(key + ":" + map.get(key));
		}

		System.out.println("===========遍历方式5:Lambda表达式===========");
		map.forEach((key, value) -> {
			System.out.println(key + ":" + value);
		});

		System.out.println("===========遍历方式6:Stream API单线程===========");
		map.entrySet().stream().forEach((entry) -> {
			System.out.println(entry.getKey() + ":" + entry.getValue());
		});

		System.out.println("===========遍历方式7:Stream API多线程===========");
		map.entrySet().parallelStream().forEach((entry) -> {
			System.out.println(entry.getKey() + ":" + entry.getValue());
		});
	}

2、LinkedHashMap(有序)

(1)底层实现(数组+双向链表(用来保持顺序)+红黑树

(2)是否有序(有序

(3)是否唯一(key唯一,value随便)

(4)是否线程安全(不安全)

(5)是否支持null(支持一个值为null的key)

value随便null不null

(6)初始容量和扩容(初始16,扩容*2)

(7)遍历方式(同HashMap)

3、HashTable(线程安全&键值都不能null)

(1)底层实现(数组+链表+红黑树

(2)是否支持null(键值都不能为null

(3)是否唯一(key唯一,value随便)

(4)是否线程安全(安全)

(5)初始容量和扩容(初始容量11,扩容2n+1)

(6)遍历方式(同HashMap,另外还有keys方法获取所有key,elements方法获取所有element)

通过map.keys().nextElement()依次获取键

通过map.elements().nextElement()依次获取值

    void testHashTable() {
		Hashtable<String, String> map = new Hashtable<String, String>();
		map.put("bb", "值1");
		map.put("aa", "值2");
		map.put("aa", "值3");
		map.put("cc", "值4");
		System.out.println("===========补充遍历方式1:keys===========");
		Enumeration<String> keys = map.keys();
		while (keys.hasMoreElements()) {
			String key = keys.nextElement();
			System.out.println(key + ":" + map.get(key));
		}
		System.out.println("===========补充遍历方式2:elements===========");
		Enumeration<String> elements = map.elements();
		while (elements.hasMoreElements()) {
			String value = elements.nextElement();
			System.out.println("key未知:"+value);
		}
	}

4、TreeMap(有序)

(1)底层实现(数组+链表+红黑树

(2)有序,继承SortedMap类

(3)是否唯一(key唯一,value随便)

(4)是否线程安全(不安全)

(5)是否支持null(键不能为null)

(6)遍历方式(同HashMap) 

(7)自定义排序(两种方式)

  • 在类中实现Comparable,重写compareTo方法
  • 在构造函数中new Comparator,匿名内部类,重写compare 方法
 TreeMap<Student, String> map = new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                if (s1.age<s2.age){
                    return 1;
                }
                if (s1.age>s2.age){
                    return -1;
                }
                return 0;
            }
        });

5、ConcurrentHashMap

ConcurrentMap,它是一个接口,是一个能够支持并发访问的java.util.map集合; ConcurrentHashMap是一个线程安全,并且是一个高效的HashMap

五、总结

1、是否可重复

  • 所有Set都不允许重复
  • 所有List都可以重复
  • 所有Map的key都不能重复

2、是否允许null

  • 所有Set都允许一个null
  • 所有List都允许多个null
  • HashTable和ConcurrentHashMap键值对都不允许是null,TreeMap不允许键是null,值可以,其余的Map都允许有一个键为null

3、是否线程安全

  • Set都不安全
  • List中Vector安全
  • Map中HashTable,ConcurrentHashMap安全

4、是否有序

  • HashSet无序,LinkedHashSet和TreeSet有序(但LinkedHashSet是按照存放的顺序排序,TreeSet是按照指定的规则排序(Comparable接口的compareTo方法)
  • List都有序
  • LinkedHashMap和TreeMap有序,其余的其实不是百分百有序,会受初始化大小影响(但LinkedHashMap是按照存放的顺序排序,TreeMap是按照指定的规则排序(Comparable接口的compareTo()方法,或者写匿名内部类Comparator类的compare()方法)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值