概述
目录
类集
链表
原理图
链表和二叉树伪代码结构
栈
队列
红黑树
Collection接口
List接口
ArrayList常用方法
Vector
LinkedList常用方法
Iterator与ListIterator
foreach
Set
Map
HashMap
HashMap实现原理
Java中Map常用方法总结以及遍历方式的汇总
Map三大常用功能方法表格整理
HashMap/Hashtable/ConcurrentHashMap/TreeMap/LinkedMap之间的区别
哈希表的初始容量和散列因子
存储自定义对象
JDK 9 集合新特性
类集
类集是什么:Java用于实现数据结构的库,在java.util包中。
链表
定义:链表 [Linked List]:链表是由一组不必相连(不必相连:可以连续也可以不连续)的内存结构(节点),按特定的顺序链接在一起的抽象数据类型。
原理图
链表和二叉树伪代码结构
栈
队列
红黑树
Collection接口
Collection 接口是在整个 Java 类集中保存单值的最大操作父接口,里面每次操作的时候都只能保存一个对象的数据。 此接口定义在 java.util 包中。
本接口中一共定义了 15 个方法,那么此接口的全部子类或子接口就将全部继承以上接口中的方法。
但是,在开发中不会直接使用 Collection 接口。而使用其操作的子接口:List、Set。
List接口
在整个集合中 List 是 Collection 的子接口,里面的所有内容都是允许重复的。
此接口的实现类,常用的实现类有如下几个:
ArrayList(95%)、Vector(4%)、LinkedList(1%)
-
Array和Vetor采用的是动态数组来存储,LinkList采用的是双向链表来实现,可以模拟栈和队列。
ArrayList常用方法
下面是总结了一些比较常用的ArrayList类成员方法:
-
增加元素到链表中
-
boolean add(Element e)
增加指定元素到链表尾部. -
void add(int index, Element e)
增加指定元素到链表指定位置.
-
-
从链表中删除元素
-
void clear()
从链表中删除所有元素. -
E remove(int index)
删除链表中指定位置的元素. -
protected void removeRange(int start, int end)
删除链表中从某一个位置开始到某一个位置结束的元素。
-
-
获取链表中的元素
-
E get(int index)
获取链表中指定位置处的元素. -
Object[] toArray()
获取一个数组,数组中所有元素是链表中的元素.(即将链表转换为一个数组)
-
-
修改某个元素
-
E set(int index, E element)
将链表中指定位置上的元素替换成新元素。
-
-
搜索元素
-
boolean contains(Object o)
如果链表包含指定元素,返回true. -
int indexOf(Object o)
返回元素在链表中第一次出现的位置,如果返回-1,表示链表中没有这个元素。 -
int lastIndexOf(Object o)
返回元素在链表中最后一次出现的位置,如果返回-1,表示链表中没有这个元素。
-
-
检查链表是否为空
-
boolean isEmpty()
返回true表示链表中没有任何元素.
-
-
获取链表大小
-
int size()
返回链表长度(链表包含元素的个数).
-
以上是ArrayList类中使用比较多的成员方法。
Vector
方法与ArrayList基本相同
LinkedList常用方法
集合 的体系: ------------| Collection 单例集合的根接口 ----------------| List 如果是实现了List接口的集合类,具备的特点: 有序,可重复。 -------------------| ArrayList ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。 -------------------| LinkedList LinkedList 底层是使用了链表数据结构实现的, 特点: 查询速度慢,增删快。 -------------------| Vector(了解即可) 底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。
----------------| Set 如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。 -------------------| HashSet 底层是使用了哈希表来支持的,特点: 存取速度快. -------------------| TreeSet 如果元素具备自然顺序 的特性,那么就按照元素自然顺序的特性进行排序存储。
Linkedlist特有的方法: 1:方法介绍 addFirst(E e) addLast(E e)
getFirst() getLast()
removeFirst() removeLast()
2:数据结构 1:栈 (1.6) : 主要是用于实现堆栈数据结构的存储方式。 先进后出 push() pop() 2:队列(双端队列1.5): 主要是为了让你们可以使用LinkedList模拟队列数据结构的存储方式。 先进先出 offer() poll()
3:返回逆序的迭代器对象
descendingIterator() 返回逆序的迭代器对象
Iterator与ListIterator
//均用于取数据 //Iterator:适用于List和set //ListIterator:只适用于List ArrayList<Integer> data = new ArrayList<>(); data.add(1); data.add(2); data.add(3); data.add(4); data.add(5); // Iterator<Integer> iterator = data.iterator(); // //迭代器使用的是指针 // //iterator.hasNext()是将指针指向下一个位置,看是否存在数据,返回的是布尔值 // /* // while (iterator.hasNext()){ // Integer i =iterator.next();//iterator.next():将指针往下移动一个位置 // System.out.println(i); // } // // iterator.next(); // //在remove前一定要用next()方法取到位置,因为只有这样把指针移动到有值得地方才能删除 // iterator.remove(); // System.out.println(data.size()); ListIterator<Integer> iterator = data.listIterator(); iterator.add(100); //添加是在索引0的前面添加,索引下面指针移动需要3次 iterator.next();//指针指向索引0 iterator.next();//指针指向索引1 iterator.set(200); System.out.println(data.size()); iterator.previous();//指针从下往上移动一位 iterator.previous(); iterator.previous(); while (iterator.hasNext()){ System.out.println(iterator.next()); }
foreach
-
foreach:增强For循环,最早出现在C#中
-
用于迭代数组 或 集合(Collection接口下的类)
-
语法:for(数据类型 变量名:集合或数组名){}
for (String s:set){ System.out.println(s); }
Set
-
不包含重复元素的集合。 更正式地说,集合不包含元素对
e1
和e2
,使得e1.equals(e2)
和最多一个null元素。 正如其名称所暗示的,此接口模拟数学集抽象。 -
注意:如果将可变对象用作set元素,则必须非常小心。 如果在对象是集合中的元素时以影响equals比较的方式更改对象的值,则不指定集合的行为。
HashSet
储存数据的方式:以散列表的形式进行无序存放。
HashSet<String> set = new HashSet<>(); boolean flag1 =set.add("锄禾日当午"); set.add("汗滴禾下土"); set.add("谁知盘中餐"); set.add("粒粒皆辛苦"); boolean flag2 =set.add("锄禾日当午"); System.out.println(flag1); System.out.println(flag2);//存入重复元素,返回false Iterator<String> iterator = set.iterator(); for (String s:set){ //因为哈希表也是散列表,数据在散列表中的存储顺序不能确定,所以打印出来的 System.out.println(s); } //打印set里面的内容 /*while (iterator.hasNext()){ System.out.println(iterator.next()); }*/
TreeSet
-
储存数据的方式:以二叉树的形式进行有序存放。
-
排序是根据字符的ASCII码进行排序
TreeSet<String> data = new TreeSet<>(); data.add("b"); data.add("c"); data.add("a"); data.add("d"); for (String s:data){ System.out.println(s); } //System.out.println((char)1); //打印ASCII的方法
Map
-
collection是单值储存集合,map是双值储存集合(键值对)。
-
Map是将键映射到值的对象。 不能包含重复的键; 每个键最多可以映射一个值。
-
map集合的键(key)不可重复。大多数Set集合是用了map的键来存储数据,来实现数据的不可重复性。
HashMap
-
哈希表(hashmap),又称为散列表,是以对象数组+链表的形式进行储存。即把数组看作二维数组,在数组的某个索引中插入链表进行存储。其中,数组的索引我们又称为哈希桶。
-
如何得到哈希表?通过哈希码(hashcode)对数组长度取余,得到的余数就是数据存放的哈希桶编号。当有两个以上的数据放在同一个哈希桶中,那么就会使用链表的形式对这两个数据进行储存。
-
当哈希桶中的数据量大于8时,从链表转换为红黑二叉树
-
当哈希值中的数据量减少到6时,从红黑二叉树转换为链表
-
当哈希桶中的数据量等于7时,那么请问当数据量减少到6时,哈希表需要转换为链表吗?
-
我们确定哈希桶数据量为7时,该形式是二叉树还是链表。如果数据量为7时,还是链表,又怎么用得着转为链表呢
-
-
-
使用默认初始容量(16)和默认加载因子(0.75)构造一个空
HashMap
。 -
散列因子的作用:当散列因子达到某阈值时,对象数组将进行动态扩容。比如下面这个初始桶数量为16,散列因子(加载因子)0.75,当数组的桶容量达到75%时,数组容量将扩大一倍,桶数量达到32.
HashMap实现原理
Java中Map常用方法总结以及遍历方式的汇总
一、整理:
看到array,就要想到角标。
看到link,就要想到first,last。
看到hash,就要想到hashCode,equals.
看到tree,就要想到两个接口。Comparable,Comparator。
二、Map与Collection在集合框架中属并列存在
1.Map存储的是键值对
2.Map存储元素使用put方法,Collection使用add方法
3.Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素
4.Map集合中键要保证唯一性
也就是Collection是单列集合, Map 是双列集合。
总结:
Map一次存一对元素, Collection 一次存一个。Map 的键不能重复,保证唯一。
Map 一次存入一对元素,是以键值对的形式存在.键与值存在映射关系.一定要保证键的唯一性.
三、Map中常见方法:
1、添加:
1、V put(K key, V value) (可以相同的key值,但是添加的value值会覆
盖前面的,返回值是前一个,如果没有就返回null)
2、putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关
系复制到此映射中(可选操作)。
2、删除
1、remove() 删除关联对象,指定key对象
2、clear() 清空集合对象
3、获取
1:value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候,返
回的是null。
3、判断:
1、boolean isEmpty() 长度为0返回true否则false
2、boolean containsKey(Object key) 判断集合中是否包含指定的key
3、boolean containsValue(Object value) 判断集合中是否包含指定的value
4、长度:
Int size()
四、遍历Map的方式:
1、将map 集合中所有的键取出存入set集合。
Set<K> keySet() 返回所有的key对象的Set集合,再通过get方法获取键对应的值。
2、 values() ,获取所有的值.
Collection<V> values()不能获取到key对象
3、 Map.Entry对象 推荐使用 重点
Set<Map.Entry<k,v>> entrySet() 将map 集合中的键值映射关系打包成一个对象。
Map.Entry对象通过Map.Entry 对象的getKey,getValue获取其键和值。
第一种方式:使用keySet
将Map转成Set集合(keySet()),通过Set的迭代器取出Set集合中的每一个元素(Iterator)就是Map集合中的所有的键,再通过get方法获取键对应的值。
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class Demo1 { public static void main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); map.put(1, "aaaa"); map.put(2, "bbbb"); map.put(3, "cccc"); System.out.println(map); // // 获取方法: // 第一种方式: 使用keySet // 需要分别获取key和value,没有面向对象的思想 // Set<K> keySet() 返回所有的key对象的Set集合 Set<Integer> ks = map.keySet(); Iterator<Integer> it = ks.iterator(); while (it.hasNext()) { Integer key = it.next(); String value = map.get(key); System.out.println("key=" + key + " value=" + value); } } }
第二种方式: 通过values 获取所有值,不能获取到key对象
1 public static void main(String[] args) { 2 Map<Integer, String> map = new HashMap<Integer, String>(); 3 map.put(1, "aaaa"); 4 map.put(2, "bbbb"); 5 map.put(3, "cccc"); 6 System.out.println(map); 7 // 第二种方式: 8 // 通过values 获取所有值,不能获取到key对象 9 // Collection<V> values() 10 11 Collection<String> vs = map.values(); 12 Iterator<String> it = vs.iterator(); 13 while (it.hasNext()) { 14 String value = it.next(); 15 System.out.println(" value=" + value); 16 } 17 }
第三种方式: Map.Entry
public static interface Map.Entry<K,V> 通过Map中的entrySet()方法获取存放Map.Entry<K,V>对象的Set集合。
Set<Map.Entry<K,V>> entrySet() 面向对象的思想将map集合中的键和值映射关系打包为一个对象,就是Map.Entry,将该对象存入Set集合,Map.Entry是一个对象,那么该对象具备的getKey,getValue获得键和值。
1 public static void main(String[] args) { 2 Map<Integer, String> map = new HashMap<Integer, String>(); 3 map.put(1, "aaaa"); 4 map.put(2, "bbbb"); 5 map.put(3, "cccc"); 6 System.out.println(map); 7 // 第三种方式: Map.Entry对象 推荐使用 重点 8 // Set<Map.Entry<K,V>> entrySet() 9 10 11 // 返回的Map.Entry对象的Set集合 Map.Entry包含了key和value对象 12 Set<Map.Entry<Integer, String>> es = map.entrySet(); 13 14 Iterator<Map.Entry<Integer, String>> it = es.iterator(); 15 16 while (it.hasNext()) { 17 18 // 返回的是封装了key和value对象的Map.Entry对象 19 Map.Entry<Integer, String> en = it.next(); 20 21 // 获取Map.Entry对象中封装的key和value对象 22 Integer key = en.getKey(); 23 String value = en.getValue(); 24 25 System.out.println("key=" + key + " value=" + value); 26 } 27 }
Map三大常用功能方法表格整理
插入和删除元素(表 2 )。
表 2:Map 更新方法: 可以更改 Map 内容。
clear() | 从 Map 中删除所有映射 |
---|---|
remove(Object key) | 从 Map 中删除键和关联的值 |
put(Object key, Object value) | 将指定值与指定键相关联 |
clear() | 从 Map 中删除所有映射 |
putAll(Map t) | 将指定 Map 中的所有映射复制到此 map |
查看 Map
表 3:返回视图的 Map 方法: 使用这些方法返回的对象,您可以遍历 Map 的元素,还可以删除 Map 中的元素。
entrySet() | 返回 Map 中所包含映射的 Set 视图。Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() 和 getValue() 方法(还有一个 setValue() 方法)访问后者的键元素和值元素 |
---|---|
keySet() | 返回 Map 中所包含键的 Set 视图。删除 Set 中的元素还将删除 Map 中相应的映射(键和值) |
values() | 返回 map 中所包含值的 Collection 视图。删除 Collection 中的元素还将删除 Map 中相应的映射(键和值) |
访问元素
表 4:Map 访问和测试方法: 这些方法检索有关 Map 内容的信息但不更改 Map 内容。
get(Object key) | 返回与指定键关联的值 |
---|---|
containsKey(Object key) | 如果 Map 包含指定键的映射,则返回 true |
containsValue(Object value) | 如果此 Map 将一个或多个键映射到指定值,则返回 true |
isEmpty() | 如果 Map 不包含键-值映射,则返回 true |
size() | 返回 Map 中的键-值映射的数目 |
HashMap/Hashtable/ConcurrentHashMap/TreeMap/LinkedMap之间的区别
他们的区别主要在于线程安全的问题
HashMap:线程不安全,但效率快。如图1
Hashtable:线程安全,但效率慢。如图2
ConcurrentHashMap:采用分段锁机制,保证线程安全,效率又比较高,如图3
TreeMap:有序的排队集合
LinkedMap:采用哈下表+双向链表的结构,能够保证按元素添加的顺序进行存储。但是HashMap不会,比如说先存放的元素可能被存放于索引较后的数组中。
(图1)
如图1所示,ABC是同时独立操作数据,这样会造成数据错乱等线程不安全问题。比如:A往hashMap存了半碗水,然后B把A存的这半碗水取出来喝掉了,C往hashmap中存了半碗水。而A是不知道B,C的存在的,那么他就以为C存的那半碗水是自己存的那半碗。这样就是数据错乱问题。
hashmap允许同时操作数据,效率高,如果只是只做存或只做取数据时,hashmap不会有线程不安全问题。
图2
Hashtable采用的是顺序操作模式,能够有效防止数据错乱的问题,但是效率低。
图3
ConcurrentHashMap采用的是哈希表进行储存,首先通过对象数组的索引进行存储数据,这一步是不用顺序操作的,能够同步进行,因为数组的各个索引内容互不干扰。而在数组内部的哈希桶中,是采用顺序操作的方式,来保证数据不发生错乱。
哈希表的初始容量和散列因子
HashMap的实例有两个影响其性能的参数: 初始容量和负载因子 。 容量是哈希表中的桶数,初始容量只是创建哈希表时的容量。 加载因子是在自动增加容量之前允许哈希表获取的完整程度的度量。 当哈希表中的条目数超过加载因子和当前容量的乘积时,哈希表将被重新哈希(即,重建内部数据结构),以便哈希表具有大约两倍的桶数。
-
散列因子越大,越节省空间,但查询效率低
-
散列因子越小,越浪费空间,但查询效率高。
存储自定义对象
-
当我们以HashMap存储数据时,不应该更改其key的值。
-
如果确实要更改,那么就不要用hashMap这种数据结构来存储key。
HashMap<Book,String> data = new HashMap<Book, String>(); Book book1 = new Book("金苹果","讲述了苹果种植的辛酸路程"); data.put(book1,"我们人生的第一本书"); Book book2 = new Book("银苹果","讲述了苹果种植的辛酸路程"); data.put(book2,"我们人生的第二本书"); //哈希值是通过key和value计算出来的。 // 因为下面更改了key(book1),哈希值重新计算了,没有找到之前存放数据的哈希桶,从而没有找到value,返回null。 book1.setName("铜苹果"); System.out.println(data.get(book1)); //更可怕的是,当数据存到一定量时,哈希表重新散列。此时book1的键会重新按照铜苹果进行存储。 //这样又会出现我们一直以为key是金苹果,但实际是铜苹果这种尴尬的问题。 Book book3 = new Book("金苹果","讲述了苹果种植的辛酸路程"); //按道理,我们通过book3的键对去取,应该能找到Book1的value("我们人生的第一本书") //除了要比较哈希值,系统还有比较equals。 // 虽然Book1和Book3的哈希值可能相同,但是因为Book1把name改为了铜苹果,所以equals为False,也是同样地找不到数据 System.out.println(data.get(book3)); //因此,当我们以HashMap存储数据时,不应该更改其key的值。 // 如果确实要更改,那么就不要用hashMap这种数据结构来存储key。
JDK 9 集合新特性
//JDK 9 集合新特性:List,Set,HashMap均有of()方法来设置内容 //集合长度一旦设定了,不可修改。 public static void main(String[] args) { List<String> list = List.of("锄禾日当午","汗滴禾下土"); //list.add("谁知盘中餐");//由于集合长度一旦设定了,不可修改的特性,运行此代码时会报错。 for (String s : list){ System.out.println(s); } Set<String> set = Set.of("一二三四五","上山打老虎"); for (String s : set){ System.out.println(s); } Map<String,String> map = Map.of("haha1","锄禾日当午","haha2","汗滴禾下土"); Set<String> keyset = map.keySet(); for (String key:keyset){ System.out.println(key+"->"+map.get(key)); } }
最后
以上就是大力红牛为你收集整理的JavaEE笔记——集合类集链表栈队列红黑树Collection接口Map的全部内容,希望文章能够帮你解决JavaEE笔记——集合类集链表栈队列红黑树Collection接口Map所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复