Java 集合合集
2021/12/27 9:07:13
本文主要是介绍Java 集合合集,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
【韩顺平讲Java】Java集合专题 -ArrayList HashMap HashSet List Map TreeMap
01----集合的理解和好处
- 可以动态保存任意多个对象,比较方便。
- 提供了一系列操作对象的方法:
add()
,remove()
,set()
,get()
。
02----集合的框架体系
- 单列集合
- 双列集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cotMTIEA-1640566300154)(E:[HanShunping] Java Collection\笔记\01.png)]
03----集合的常用方法
import java.util.ArrayList; import java.util.List; public class CollectionMethod { public static void main(String[] args) { List list = new ArrayList(); //add 添加元素 list.add("jack"); list.add(10); list.add(true); //remove 删除元素 list.remove(0); //删除第一个元素 list.remove(true); System.out.println(list); //contains 查找元素是否存在 System.out.println(list.contains("jack")); //size 获取元素个数 System.out.println(list.size()); //isEmpty 判断是否为空 System.out.println(list.isEmpty()); //clear 清空 list.clear(); //addAll 添加多个元素 List list2 = new ArrayList(); list2.add("wang"); list2.add(100); list.addAll(list2); //cintainsAll 查找多个元素是否都存在 list.containsAll(list2); //removeAll 删除多个元素 list.removeAll(list2); } }
04----迭代器遍历
iterator.hasNext()
:判断是否有下一个元素。
import java.util.ArrayList; import java.util.Iterator; public class CollectionIterator { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("Wang"); arrayList.add("Zhao"); arrayList.add("Qian"); //生成迭代器 Iterator iterator = arrayList.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } } }
05----增强 for
循环
增强 for
底层仍然是迭代器。
for(Object obj : arrayList){ System.out.println(obj); }
07----List
接口方法
- 有序可重复(添加,取出顺序一致)
- 支持索引
- 可根据序号存取容器中的元素
ArrayList
线程不安全,效率高Vector
线程安全LinkedList
线程不安全
add(int index, Object ele)
:在 index 位置插入 ele 元素
addAll(int index, Collection eles)
:从 index 位置开始将 eles 中所有元素添加进去
get(int index)
:获取指定位置的元素
indexOf(Object obj)
:返回 obj 首次出现的位置
lastIndexOf()
:
remove(int index)
:删除指定位置的元素,并返回此元素
set(int index, Object ele)
:设置指定位置的元素为 ele
subList(int fromIndex, int toIndex)
:返回从 fromIndex 到 toIndex 位置的子集合
12----ArrayList
底层结构和源码分析
ArrayList
中维护了一个Object
类型的数组elementData
,transient Object[] elementData
。- 当创建
ArrayList
对象时,如果使用的是无参构造器,则初始elementData
容量为0,第一次添加数据时扩容elementData
为10,如需要再次扩容,则按照 1.5倍 增加。 - 当使用指定大小的构造器时,则初始
elementData
容量为指定大小,如需要扩容,则按照 1.5倍 增加。
16----Vector
底层结构和源码分析
Vector
中维护了一个Object
类型的数组elementData
,transient Object[] elementData
。- 当创建
Vector
对象时,如果使用的是无参构造器,则默认elementData
容量为10,如需要扩容,则按照 2倍 增加。 - 当使用指定大小的构造器时,则初始
elementData
容量为指定大小,如需要扩容,则按照 2倍 增加。
17----LinkedList
底层结构和源码分析
- LinkedList
的底层操作机制
LinkedList
底层维护了一个双向链表- 维护了两个属性
first
和last
分别指向首节点和尾节点 - 每个节点
Node对象
里面又维护了prev
,next
,item
三个属性,其中通过prev
指向前一个,next
指向后一个节点,最终实现双向链表 - 所以
LinkedList
的元素的添加和删除不是通过数组完成的,相对说效率较高
20----Set
接口和常用方法
- 无序不可重复
- 没有索引
21----HashSet
HashSet
实现了Set
接口HashSet
实际上是HashMap
- 可以存放
null
值,但只能有一个 HashSet
不保证元素是有序的,取决于hash
后,再确定索引结果- 元素,对象不可重复
经典Java
面试题:
Set set = new HashSet(); set.add(new Dog("tom")); //Ok set.add(new Dog("tom")); //Ok set.add(new String("hsp")); //Ok set.add(new String("hsp")); //false
22----数组链表模拟
Node[] table = new Node[16]; Node john = new Node("john", null); table[2] = john; Node jack = new Node("jack", null); john.next = jack; //jack挂载到john后 class Node{ Object item; Node next; //单向链表 public Node(Object item, Node next){ this.item = item; this.next = next; } }
23----HashSet
扩容机制
-
分析
HashSet
的添加元素底层是如何实现的(hash()+equals()
)HashSet
底层是HashMap
- 添加一个元素时,先得到
hash
值,然后转成索引值 - 找到存储数据表
table
,看这个索引值位置是否已经存放有元素 - 如果没有,则直接存入
- 如果有,调用
equals
比较,如果相同就放弃添加,若果不同,则向后添加 - 在
java8
中,如果一条链表的元素个数超过默认8,且table的大小大于等于默认64时,则进行树化(红黑树)
-
分析
HashSet
的扩容和转成红黑树的机制HashSet
底层是HashMap
,第一次添加时,table
数组扩容到16,临界值是16*0.75(加载因子)=12- 如果
table
数组到了临界值12,就会扩容到16×2(2倍扩容)=32,新的临界值就是24,以此类推 - 在
java8
中,只有一条链表的元素个数超过默认8,且table
的大小大于等于默认64时,才会进行树化(红黑树),否则仍采用数组扩容机制
-
加载因子为何是0.75?
- 加载因子越大
hash
表(table
)数据密度越大,发生碰撞的几率越高,数组(table
)中的链表越容易长,造成查询或插入时的比较次数增多,性能会下降。 - 加载因子越小,就越容易触发扩容,数据密度也越小,意味着发生碰撞的几率越小,数组中的链表也就越短,查询和插入时比较的次数也越小,性能会更高。但是会浪费一定的内存空间。而且经常扩容也会影响性能。
- 源码中有:在理想情况下,使用随机哈希码,节点出现的频率在
hash
桶中遵循泊松分布,当桶中元素到达8个的时候,概率已经变得非常小,也就是说用0.75作为加载因子,每个碰撞位置的链表长度超过8个是几乎不可能的。
- 加载因子越大
28----HashSet
最佳实战
import java.util.HashSet; import java.util.Objects; public class HashSetExc { public static void main(String[] args) { HashSet hashSet = new HashSet(); hashSet.add(new Employee("milan",18)); hashSet.add(new Employee("jackie",28)); hashSet.add(new Employee("milan",18)); // 若果不重写equals方法,则三个对象是不同对象都能被添加 // 重写后名字年龄相同的对象视为相同对象,则第三个对象无法添加 System.out.println("hashSet == "+ hashSet); } } class Employee{ private String name; private int age; public Employee() { } public Employee(String name, int age) { 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 boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Employee employee = (Employee) o; return age == employee.age && Objects.equals(name, employee.name); } @Override public int hashCode() { return Objects.hash(name, age); } }
33----Map
接口特点
Map
用于保存具有映射关系的数据:Key-Value
Map
中的Key
和Value
可以是任何引用类型的数据Map
中的Key
不允许重复,原因和HashSet
一样Map
中的Value
可以重复Map
中的Key
可以为null
,value
也可以为null
,注意key
为null
只能有一个- 常用
String
类作为Map
中的key
key
和value
存在单向一一对应关系,即通过指定key
总能找到对应的value
Map
的k-v
存放在Node
中
35----Map
的常用方法
put
:添加remove
:根据key
删除映射关系get
:根据key
获取值size
:获取元素个数isEmpty
:判断是否为空clear
:清除containsKey
:查找key
是否存在
39----HashMap
扩容机制
- 扩容机制和
HashSet
相同HashMap
底层维护了Node
类型的数组table
,默认为null
- 当创建
HashMap
对象时,将加载因子(loadfactor
)初始化为0.75 - 当添加
k-v
时,通过key
的hash
值得到在table
的索引,然后判断该索引处是否有元素,如果么有则直接添加;如果有则继续判断该元素的key
是否和准备加入的元素key
相等,如果相等则替换value
,如果不相等需要判断是树结构还是链表结构做出相应处理。如果添加时发现容量不够,则需要扩容 - 第一次添加元素则需要扩容
table
容量为16,临界值12 - 以后再扩容,按照***2倍***增加
- 在
java8
中,如果一条链表的元素个数超过默认8,且table
的大小大于等于默认64时,则进行树化(红黑树)
42----HashTable
基本介绍
- 存放的元素是键值对:
k-v
- 键和值都不能为
null
- 使用方法与
HashMap
基本一致 HashMap
线程不安全,HashTable
线程安全(加了同步synchronized
)
43----HashTable
扩容
- 底层有数组
Hashtable$Entry[]
,初始化大小为11 - 临界值:
11*0.75=8
- 当大于临界值时,按照***
2倍+1
***的方式扩容
HashMap
与HashTable
的对比:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4RRxSla-1640566300157)(https://www.bilibili.com/video/BV1YA411T76k?p=43)]
45----开发中如何选择集合实现类
- 先判断存储的类型(一组对象【单列】或一组键值对【双列】)
- 一组对象:
Collection
接口- 允许重复:
List
(有序可重复)- 增删多:
LinkedList
【底层维护了一个双向链表】 - 改查多:
ArrayList
【底层维护了Object
类型的可变数组】
- 增删多:
- 不许重复:
Set
(无序不可重复)- 无序:
HashSet
【底层是HashMap
,维护了哈希表,即数组+链表+红黑树】 - 排序:
TreeSet
- 插入和取出顺序一致:
LinkedHashSet
【维护了数组+双向链表】
- 无序:
- 允许重复:
- 一组键值对:
Map
- 键无序:
HashMap
【底层是哈希表(jdk1.7
:数组+链表,jdk1.8
:数组+链表+红黑树)】 - 键排序:
TreeMap
- 键插入和取出顺序一致:
LinkedHashMap
- 读取文件:
Properties
- 键无序:
46----TreeSet
介绍
- 当使用无参构造器
new TreeSet()
时,仍然是无序的 - 使用
TreeSet
提供的一个构造器,可以传入比较器,从而使得其有序
47----TreeMap
介绍
与TreeSet
基本一致,区别在于TreeMap
存入的是键值对k-v
- 当使用无参构造器
new TreeSet()
时,仍然是无序的 - 使用
TreeSet
提供的一个构造器,可以传入比较器,从而使得其有序
48----Collections
工具类
Collections
是一个操作Set,List,Map
等集合的工具类- 提供了一系列方法
import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; public class Collections_ { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("Jack"); arrayList.add("Tom"); arrayList.add("Moon"); arrayList.add("McGrady"); System.out.println(arrayList); //reverse(List):翻转其中元素 Collections.reverse(arrayList); System.out.println(arrayList); //shuffle(List):随机排序 Collections.shuffle(arrayList); System.out.println(arrayList); //sort(List):根据元素自然顺序排序 Collections.sort(arrayList); System.out.println(arrayList); //sort(List,Comparator):根据指定的比较器对其排序 Collections.sort(arrayList, new Comparator() { @Override public int compare(Object o1, Object o2) { return ((String)o1).length() - ((String)o2).length(); } }); System.out.println("按字符串长度排序:"+arrayList); //swap(List,int,int):交换i和j处的元素 Collections.swap(arrayList,0,3); System.out.println(arrayList); //Object max(Collection):根据元素自然排序,返回集合中最大元素 //Object max(Collection,Comparator): //Object min(Collection): //Object min(Collection,Comparator): //int frequency(Collection,Object):返回指定元素的出现次数 //void copy(List dest,List src):将src内容复制到dest中,注意dest必须大于等于src的长度 //boolean replaceAll(List list, Object oldVal, Object newVal):用新值替换list中的旧值 } }
50----作业
作业一:
import java.util.ArrayList; @SuppressWarnings({"all"}) public class Homework01 { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add(new News("新冠确诊病例超千万,数百万印度教信徒赴恒河\"圣浴\"引民众担忧")); arrayList.add(new News("男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生")); int size = arrayList.size(); //倒序遍历 for (int i = size - 1; i >= 0; i--) { //System.out.println(arrayList.get(i)); News news = (News)arrayList.get(i); System.out.println(processTitle(news.getTitle())); } } //专门写一个方法,处理现实新闻标题 process处理 public static String processTitle(String title) { if(title == null) { return ""; } if(title.length() > 15) { return title.substring(0, 15) + "..."; //[0,15) } else { return title; } } } /** * 按要求实现: * (1) 封装一个新闻类,包含标题和内容属性,提供get、set方法,重写toString方法,打印对象时只打印标题; * (2) 只提供一个带参数的构造器,实例化对象时,只初始化标题;并且实例化两个对象: * 新闻一:新冠确诊病例超千万,数百万印度教信徒赴恒河“圣浴”引民众担忧 * 新闻二:男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生 * (3) 将新闻对象添加到ArrayList集合中,并且进行倒序遍历; * (4) 在遍历集合过程中,对新闻标题进行处理,超过15字的只保留前15个,然后在后边加“…” * (5) 在控制台打印遍历出经过处理的新闻标题; */ class News { private String title; private String content; public News(String title) { this.title = title; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } @Override public String toString() { return "News{" + "title='" + title + '\'' + '}'; } }
作业二:
import java.util.ArrayList; import java.util.Iterator; @SuppressWarnings({"all"}) public class Homework02 { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); Car car = new Car("宝马", 400000); Car car2 = new Car("宾利",5000000); //1.add:添加单个元素 arrayList.add(car); arrayList.add(car2); System.out.println(arrayList); //* 2.remove:删除指定元素 arrayList.remove(car); System.out.println(arrayList); //* 3.contains:查找元素是否存在 System.out.println(arrayList.contains(car));//F //* 4.size:获取元素个数 System.out.println(arrayList.size());//1 //* 5.isEmpty:判断是否为空 System.out.println(arrayList.isEmpty());//F //* 6.clear:清空 //System.out.println(arrayList.clear();); //* 7.addAll:添加多个元素 System.out.println(arrayList); arrayList.addAll(arrayList);//2个宾利 System.out.println(arrayList); //* 8.containsAll:查找多个元素是否都存在 arrayList.containsAll(arrayList);//T //* 9.removeAll:删除多个元素 //arrayList.removeAll(arrayList); //相当于清空 //* 使用增强for和 迭代器来遍历所有的car , 需要重写 Car 的toString方法 for (Object o : arrayList) { System.out.println(o);// } System.out.println("===迭代器==="); Iterator iterator = arrayList.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); System.out.println(next); } } } /** * 使用ArrayList 完成对 对象 Car {name, price} 的各种操作 * 1.add:添加单个元素 * 2.remove:删除指定元素 * 3.contains:查找元素是否存在 * 4.size:获取元素个数 * 5.isEmpty:判断是否为空 * 6.clear:清空 * 7.addAll:添加多个元素 * 8.containsAll:查找多个元素是否都存在 * 9.removeAll:删除多个元素 * 使用增强for和 迭代器来遍历所有的car , 需要重写 Car 的toString方法 */ class Car { private String name; private double price; public Car(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Car{" + "name='" + name + '\'' + ", price=" + price + '}'; } }
作业三:
import java.util.*; @SuppressWarnings({"all"}) public class Homework03 { public static void main(String[] args) { Map m = new HashMap(); m.put("jack", 650);//int->Integer m.put("tom", 1200);//int->Integer m.put("smith", 2900);//int->Integer System.out.println(m); m.put("jack", 2600);//替换,更新 System.out.println(m); //为所有员工工资加薪100元; //keySet Set keySet = m.keySet(); for (Object key : keySet) { //更新 m.put(key, (Integer)m.get(key) + 100); } System.out.println(m); System.out.println("=============遍历============="); //遍历 EntrySet Set entrySet = m.entrySet(); //迭代器 Iterator iterator = entrySet.iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry)iterator.next(); System.out.println(entry.getKey() + "-" + entry.getValue()); } System.out.println("====遍历所有的工资===="); Collection values = m.values(); for (Object value : values) { System.out.println("工资=" + value); } } } /** * 按要求完成下列任务 * 1)使用HashMap类实例化一个Map类型的对象m,键(String)和值(int)分别用于存储员工的姓名和工资, * 存入数据如下: jack—650元;tom—1200元;smith——2900元; * 2)将jack的工资更改为2600元 * 3)为所有员工工资加薪100元; * 4)遍历集合中所有的员工 * 5)遍历集合中所有的工资 */
作业四:试分析HashSet
和TreeSet
分别如何实现去重?
HashSet
的去重机制:hashcode()+equals()
,底层先通过存入的对象运算得到一个hash
值,通过hash
值得到对应的索引,如果发现table
索引值所在的位置没有数据,就直接存放;如果有数据,就使用equals()
比较,比较后如果不相同就加入,否则不加入。TreeSet
的去重机制:如果传入了一个Comparator
匿名对象,就使用实现的compare()
去重,如果方法返回0,就认为是相同的元素,不添加;如果没有传入Comparator
匿名对象,则以添加的对象实现的Comparable
接口的compareTo()
方法去重。
import com.hspedu.map_.TreeMap_; import java.util.TreeMap; import java.util.TreeSet; @SuppressWarnings({"all"}) public class Homework04 { public static void main(String[] args) { TreeSet treeSet = new TreeSet(); treeSet.add("hsp"); treeSet.add("tom"); treeSet.add("king"); treeSet.add("hsp");//加入不了, 因为String的compareTo()方法比较的是内容 System.out.println(treeSet); } }
作业五:
//import java.util.TreeSet; //@SuppressWarnings({"all"}) //public class Homework05 { // public static void main(String[] args) { // TreeSet treeSet = new TreeSet(); // //分析源码 // //add 方法,因为 TreeSet() 构造器没有传入Comparator接口的匿名内部类 // //所以在底层 Comparable<? super K> k = (Comparable<? super K>) key; // //即 把 Perosn转成 Comparable类型 // treeSet.add(new Person());//ClassCastException. // treeSet.add(new Person());//ClassCastException. // treeSet.add(new Person());//ClassCastException. // treeSet.add(new Person());//ClassCastException. // treeSet.add(new Person());//ClassCastException. // // System.out.println(treeSet); // // } //} // //class Person implements Comparable{ // // @Override // public int compareTo(Object o) { // return 0; // } //}
作业六:
import java.util.HashSet; import java.util.Objects; @SuppressWarnings({"all"}) public class Homework06 { public static void main(String[] args) { HashSet set = new HashSet();//ok Person p1 = new Person(1001,"AA");//ok Person p2 = new Person(1002,"BB");//ok set.add(p1);//ok set.add(p2);//ok p1.name = "CC"; set.remove(p1); //找不到1001,CC的hash值所表示的索引,因为AA-》CC,不改变1001,AA的hash值 System.out.println(set);//2 set.add(new Person(1001,"CC")); System.out.println(set);//3 set.add(new Person(1001,"AA")); System.out.println(set);//4 } } class Person { public String name; public int id; public Person(int id, String name) { this.name = name; this.id = id; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return id == person.id && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, id); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", id=" + id + '}'; } } //===========================结果================================= /*[Person{name='BB', id=1002}, Person{name='CC', id=1001}] [Person{name='BB', id=1002}, Person{name='CC', id=1001}, Person{name='CC', id=1001}] [Person{name='BB', id=1002}, Person{name='CC', id=1001}, Person{name='CC', id=1001}, Person{name='AA', id=1001}] */
这篇关于Java 集合合集的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-27消息中间件底层原理资料详解
- 2024-11-27RocketMQ底层原理资料详解:新手入门教程
- 2024-11-27MQ底层原理资料详解:新手入门教程
- 2024-11-27MQ项目开发资料入门教程
- 2024-11-27RocketMQ源码资料详解:新手入门教程
- 2024-11-27本地多文件上传简易教程
- 2024-11-26消息中间件源码剖析教程
- 2024-11-26JAVA语音识别项目资料的收集与应用
- 2024-11-26Java语音识别项目资料:入门级教程与实战指南
- 2024-11-26SpringAI:Java 开发的智能新利器