概述
集合
什么是集合
数组也算一个集合 集合实际上就是一个容器 可以容纳其他类型的数据 在实际开发种 Java程序会将多条数据封装成多个对象 然后把多个对象放到一个集合中 将集合传到前端 然后遍历集合
注意:
集合不能直接存储基本数据类型 也不能直接存储java对象 集合当中存储的都是java对象的的内存地址 集合在Java种本身是一个容器 一个对象 在java中每一个不同的集合 底层会对应不同的数据结构 往不同的集合种存储元素 等于将数据放到了不同的数据结构中
集合的分类
1. Collection类
存储方式:单个方式存储元素
包:java.util.Collection
存放元素要求:
没有使用泛型之前 可以存放object所有子类型 使用了泛型后 只能存储某个具体类型
工具类:
java.util.Collection 集合接口 java.util.Collections 集合工具类 Collections.synchronized() 变成线程安全
Collections.sort(); 给List集合排序,要求集合中的元素实现了Comparable接口 如果想给set集合排序 可以把set转成List List<> list = new ArrarList<>(set) 不想实现Comparable接口可以用:Collections.sort(List,比较器接口);
1.1 接口常用方法
1、添加 Boolean add(E e):在集合中添加一个对象,如果添加成功,返回true,如果失败,返回false
Boolean addAll(Collection<?extend E> e):在集合中添加另一个集合,成功true,失败false;
2、删除 Boolean remove(object obj):删除一个对象,会改变集合的长度
Boolean removeAll(Colleciton con);删除一个集合,还有两个集合中相同的元素
void clear():删除所有
3、判断 Boolean contains(object obj):在集合中是否包含指定的对象
Boolean containsAll(Collection con):在集合是否包含另一个集合
Boolean isEmpty( ):判断集合是否为空
4、获取 int size( ):得到集合的尺寸大小 数组:length 字符串:length( ); 5、交集 boolean retainAll(Collection c):返回两个集合的交集元素,删除其他元素,功能和removeAll相反。 有A,B两个集合,做完交集后,A集合中的元素发生变化,取得是A和B相同的元素,B不变化。 boolean值的问题-------->只要A集合变化,那么返回true.否则false
6、集合转数组 Object[ ] toArray():把集合转换成对象。
7.迭代器: 注意:迭代器第一次不是指向第一个元素,是指向第一个前面的位置 boolean hasNext(); 如果仍有元素可以迭代 返回true Object next(); 返回迭代的下一个元素
c.add("abc"); c.add("def"); c.add(100); c.add(new Object()); Iterator it = c.iterator(); //获取迭代器 while(it.hasNext()){ Object obj = it.next(); // 取元素,且返回的元素类型是object System.out.println(obj);
注意:
集合结构只要发生改变 迭代器必须重新获取,比如删除元素之后集合结构发生改变,应该重新获取迭代器 原因: 获取迭代器对象 迭代器来遍历集合 此时相当于对当前集合的状态拍了一个快照 迭代器迭代的时候会参照这个快照进行迭代 而直接通过集合去删除元素 没有通知迭代器 会导致迭代器的快照和原集合状态不同
迭代器删除元素:
使用迭代器删除元素 it.remove(); 此时会删除迭代器中的元素 不会产生和快照参照时不同的情况
注意: 放在集合里的元素需要重写equals方法,因为object的equals方法比较的是内存地址
1.2 List
List集合存储元素特点:有序可重复,存储元素有下标。即存进去的顺序和取出来的顺序是一样的,有序是因为list集合都有下标
实现类:
ArrayList:采用数组的数据结构,是非线程安全的 LinkedList:采用双向链表数据结构 Vector:采用数组的数据结构,是线程安全的,所有的方法都有synchronized关键字修饰,所以线程安全,但效率低,所以使用较少
常用方法:
List接口继承Collection List特有方法: add(下标,元素); 在指定位置添加元素 add(元素); 向集合末尾添加元素 get(下标); 根据下标提取元素 indexof(元素); 获取指定元素第一次出现的索引 lastindexof(元素); 获取指定元素最后一次出现的索引 remove(下标) 删除指定下标的元素 set(下标 新元素); 修改指定位置的元素值
1.2.1 ArrayList
初始化容量:10
指定初始化容量 List mylist=new ArrayList(容量大小值);
集合底层:Object类型的数组、
底层先创建了一个长度为0的数组 当添加第一个元素时 初始化容量为10 集合扩容:原容量的1.5倍 建议给定一个预估计的初始化容量,减少数组的扩容次数,这是ArrayList集合比较重要的优化策略
">>":表示二进制右移一位 集合优点:
检索效率高,因为每个元素占用空间大小相同,内存地址是连续的,知道首元素的内存地址和下标,通过数学表达式计算出元素的内存地址所以检索效率高
这个集合用的最多
集合缺点:
随机增删元素效率低 但向数组末尾添加元素效率高,不受影响
数组无法存储大数据量 因为很难找到一块很大的内存空间
构造方法: Collection c = new HashSet(); List mylist = new ArrayList(c); 通过这个构造方法可以将HashSet集合转换成List集合
添加元素:
list.add();
取出元素:
list.get(下标);
遍历方式:
-
通过下标遍历
-
迭代器遍历
Iterator<String> it = list.iterator(); while(it.hasnext()){ System.out.println(it.next()); }
-
for增强
1.2.2 LinkedList
LinkedList没有初始化容量 最初这个链表中没有任何元素 first和last都是null
构造方法:
Link list = new LinkedLink(); 基本单元是节点Node
增加、取出、遍历和ArrayList一样
链表的优点: 由于链表上的元素在空间存储上内存地址不连续 所以随机增删元素的时候不会有大量元素位移 因此随即增删 效率较高 在以后的开发中 如果遇到随即增删集合中元素的业务比较多时 使用LinkedList
链表的缺点: 不能通过数学表达式计算被查找元素的内存地址 每一次查找都是从头节点开始遍历 所以LinkedList集合检索 的效率较低
总结: 检索用ArrayList
随即增删用LinkedList 注意:
ArrayList之所以检索效率较高,不是单纯因为下标的原因,是因为底层数组发挥的作用 LinkedList集合照样有下标 但是检索某个元素的时候效率比较低 因为只能从头节点开始一个一个遍历
单向链表:
对于链表数据结构 基本单元是节点Node 对于单链表数据结构 每个节点Node都有两个属性:1.存储的数据 2. 是下一个节点的内存地址
优点:随机增删元素效率高 因为增删元素不涉及到大量元素位移
缺点:查询效率较低 每一次查找某个元素的时候都需要从头节点开始往下遍历
双向链表
有下一个节点和上一个节点的内存地址
public class Node{ Node pre; Object data; Node next; }
1.2.3 Vector
底层:数组
初始化容量:10
扩容:是原容量的2倍
特点:所有方法都是线程同步的 都有synchronized关键字 线程安全效率低 使用较少
ArrayList线程不安全转线程安全:
List my = new ArrayList(); Collections.synchronizedList(my);
1.3 Set
Set集合存储元素特点:无序不可重复,存储元素没有下标。
SortedSet集合存储元素特点:由于继承了Set集合 所以无序不可重复 但是放在SortedSet集合中的元素可以自动排序,称为可排序集合 SortedMap集合的key存储元素特点:无序不可重复 放在SortedMap集合key部分的元素会自动按照大小顺序排序 称为可排序集合
实现类:
HashSet:底层是创建了HashMap集合对象,向HashSet集合中存储元素实际上存到了HashMap中 HashMap集合是一个哈希表数据结构 TreeSet:底层是创建了TreeMap集合对象,向TreeSet集合中存储元素实际上存到了TreeMap中 TreeMap集合是一个二叉树数据结构
1.3.1 HashSet
特点:无序不可重复
注意:
当向集合中添加的是自定义类型时,自定义类需要同时重写hashcode()和equals()方法
创建:
HashSet<String> set = new HashSet<>();
添加
set.add("abc");
取出:
没有下标不能通过下标取
遍历:
迭代器
Iterator<String> it = list.iterator(); while(it.hasnext()){ System.out.println(it.next()); }
for增强
for(String s:set){ System.out.println(s); }
1.3.2 TreeSet
可以排序
自定义类型需要重写CompareTo方法,或者实现比较器Comparator(建议使用匿名内部类的方式)
CompareTo方法:
package game; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class Treemap { public static void main(String[] args) { TreeMap<Integer,String> t = new TreeMap<>(); t.put(1,"ll"); t.put(6,"yy"); t.put(4,"gg"); Set<Map.Entry<Integer,String>> nodes = t.entrySet(); for(Map.Entry<Integer,String> node:nodes){ System.out.println(node.getKey()+"="+node.getValue()); } } } class A implements Comparable<A>{ int i; public A(int i){ this.i = i; } @Override public String toString() { return "A{}"; } @Override public int compareTo(A o) { return this.i-o.i; } }
实现比较器Comparator:
package game; import java.util.Comparator; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class Treemap { public static void main(String[] args) { TreeMap<Integer,String> t = new TreeMap<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1-o2; } }); t.put(1,"ll"); t.put(6,"yy"); t.put(4,"gg"); Set<Map.Entry<Integer,String>> nodes = t.entrySet(); for(Map.Entry<Integer,String> node:nodes){ System.out.println(node.getKey()+"="+node.getValue()); } } }
创建:
TreeSet<Integer> t = new TreeSet<>();
添加元素:
t.add(1);
遍历:
Iterator<Integer> it = t.iterator(); while(it.hasnext()){ System.out.println(it.next()); }
2. Map类
Map集合和Collection集合没有关系 Map集合以key-value这种键值对的方式存储元素 key和value都是存储java对象的内存地址 所有Map集合的key都是无需不可重复的
常用方法:
put(key,value); 向Map集合中添加键值对 remove(key) 根据key删除键值对 size() 获取集合中键值对的个数 values() 获取集合中所有的value返回一个Collection Set<Map.Entry<K,V>> entrySet() 将Map集合转为Set集合 Set<Map.Entry<K,V>> set = mymap.entrySet(); 注意:转换后Set集合中元素的类型是 Map.Entry<K,V>,是一种静态内部类 keySet() 获取Map集合中所有的key,所有的key是一个集合 isEmpty() 判断集合中元素个数是否为0 containsValue(value) 判断是否包含某个value containsKey(key) 判断是否包含某个key clear() 清空集合 get(key) 通过key获取value
遍历:
-
获取所有的key 遍历key来遍历value
-
foreach
-
用Set<Map.Entry<K,V>> entrySet()
Hash表:
哈希表是一个数组和单向链表的结合体 随即增删 查询效率都很高 ,增删是在数组上完成的 查询只需要部分扫描
2.1 HashMap
创建Map集合对象: Map<Integer,String> map = new HashMap<>();
HashMap集合底层:哈希表数据结构,是非线程安全的。
在JDK8之后,如果哈希表单向链表中元素超过8个,单向链表这种数据结构会变成红黑树数据结构。当红黑树上的结点数量小于6时,会重新把红黑树变成单向链表数据结构。这种方式也是为了提高检索效率,二叉树的检索会再次缩小扫描范围、提高效率。
HashMap集合key的特点:
key可以为null,但是对应的value只能有一个,value也可以为null
同一个单向链表上所有节点的hash值相同因为数组下标一样,但同一个链表上k和k的equals方法肯定返回的是false
无序是因为 不一定挂在哪个单向链表上;
不可重复是因为equals方法 如果key重复value会覆盖
放在HashMap中key部分的元素其实就是放到HashSet集合中,所以HashSet集合中的元素也需要同时重写hashcode()和equals()方法;alt+insert 可以同时生成hashcode()和equals()方法
容量:
HashMap集合的默认初始化容量是16
默认加载因子是0.75,也就是说当底层数组容量达到75%时,数组开始扩容,扩容后的容量是原来的2倍 HashMap集合初始化容量必须是2的倍数,是为了达到散列均匀,为了提高HashMap集合的存取效率
哈希表使用不当:
假设将所有的hashcode()方法返回值固定为某个值 那么会导致底层哈希表变成了纯单向链表,这种情况称为散列分布不均匀
假设将所有的hashcode()方法返回值都设定为不一样的值,会导致底层哈希表就成一维数组了,也叫散列分布不均匀 散列分布均匀需要重写hashcode()方法时有技巧
总结:
放在HashMap中key部分的元素 和 HashSet中的元素 需要同时重写hashcode()和equals()方法
重写之后 当元素eqauls为true那么hashcode值一定相同,这样就不会出现两个一样的元素出现在数组上两个位置
创建:
Map<Integer,String> map = new HashMap<>();
添加元素:
map.put(1,"liu")
获取元素个数:
map.size();
取出元素
map.get(key);
遍历:
-
拿到key遍历
Set<Integer> keys = map.keySet(); for(Integer k:keys){ System.out.println(map.get(k)) }
-
将Map集合转为Set集合 Set集合中每一个元素是Node,Node节点中有key和value
Set<Map.Entry<Integer,String>> nodes = map.entrySet(); for(Map.Entry<Integer,String> node:nodes){ System.out.println(node.getKey+"="+node.getValue()) }
2.2 HashTable
HashTable集合底层也是哈希表数据结构 线程安全 效率低
注意:
key不能为null,value也不能为null 方法带有synchronized,线程安全 效率低 底层是哈希表数据结构 初始化容量11,默认加载因子是0.75,扩容是原来的2倍+1
2.2.1 Properties
Properties被称为属性类对象,是一个Map集合,属性类,继承HashTable
特点:
线程安全,存储元素采用键值对形式
并且key和value只支持String类型 不支持其他类型
创建Properties对象:
Properties pro = new Properties();
主要构造方法:
setProperty(key,value);
存 getProperty(key);
根据key取value
2.4 TreeMap
放到TreeSet中的元素 等同于放到TreeMap集合key部分
TreeSet集合底层是一个TreeMap TreeMap集合底层是二叉树
TreeSet集合中的元素:
无序不可重复,但是可以按照元素的大小顺序自动排序 TreeSet对于自定义的类型无法排序 放在TreeSet集合中的元素需要实现java.lang.Comparable接口,并且实现compareTo方法,equals可以不写
2.4.1 比较器接口
比较器实现java.util.Comparator接口 Comparable是java.lang包下的 Compartor是java.util包下的
实现规则:
class 比较器名 implements Comparator<>{ 重写compare方法 } 传比较器对象:
TreeSet<> set = new TreeSet<>(new 比较器名);
总结:放到TreeSet或TreeMap集合key部分的元素如果需要排序 有两种方式
-
放在集合中的元素实现java.lang.Comparable接口
-
在构造TreeSet或TreeMap集合时传一个比较器对象 如果比较规则不经常变化 用Comparable接口 如果比较规则有多个且经常变化 用Comparator接口,该接口符合OCP原则
2.4.2 二叉树
自平衡二叉树: 左小右大原则 遍历二叉树的三种方式:这里的前中后说的是根的位置 前序遍历 根左右 中序遍历 左根右 后序遍历 左右根 TreeSet集合或TreeMap集合采用中序遍历 Iterator迭代器采用的是中序遍历
泛型
JDK5.0之后推出的新特性
JDK8之后引入自动类型推断机制(钻石表达式)
定义:使用泛型List<>之后 表示List集合中只允许存储固定类型的数据 所以 使用泛型可以指定集合中存储的数据类型
优点:使集合中元素的数据类型更加统一;从集合中取出的元素类型是泛型指定的类型 不需要大量向下转型
缺点:导致集合中存储的元素缺乏多样性,但大多数业务中集合元素的类型还是统一的
注意:泛型只在编译器起作用只是给编译器参考的 运行阶段没用
自定义泛型: 在类上public class Generic<标识符随便写>{} 但在new上写清楚需要什么类型 java源代码中经常出现E和T E代表element T代表type
for增强
foreach IDK5.0之后退出增强for循环
代码规范:
for(元素类型 变量名:数组或集合){}
int[] arr = [1,2,3,4,5,6]; for(int data:arr){ system.out.println(data); //data是数组中的元素 }
缺点:没有下标
优点:在集合中 可以直接取出元素 不需要再获取迭代器一个一个输出
集合总结
每个集合对象的创建 向集合中添加元素 取出元素 遍历集合
HashMap集合的key需要重写equals和hashcode
TreeSet传入的类型可以自定义 可以实现comparable接口 也可以编写一个比较器
最后
以上就是顺心老师为你收集整理的JAVA集合知识总结集合的全部内容,希望文章能够帮你解决JAVA集合知识总结集合所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复