文章目录
写在前面
java集合:主要包括两种类型,Collection 和Map。
如上图,红色的是两个根接口,蓝色的是常用实现类。
1、Iterator 迭代器
看本文第一张图,我们会发现,Collection和Map都继承自Iterator 。它是一个迭代器,是用来将集合中的元素一个一个取出来。
// Iterator 迭代器 它用来将集合里的内容一个一个取出来
// 它只有三个方法:hasNext() \ next() \ remove()
// Iterator 是一个接口,它的实现类用Collection接口中的iterator()方法返回。
Collection<String> c = new ArrayList<String>(); // 向上转型
c.add("a");
c.add("b");
c.add("c");
Iterator<String> i = c.iterator();
// hasNext()判断还有没有下一个元素,有返回true
boolean b = i.hasNext();
// next()用来取出下一个元素
String n = i.next();
// 利用循环取出集合中所有元素
// while方式
while(i.hasNext()){
System.out.println(i.next());
}
// for方式
for(Iterator<String> i1=c.iterator();i1.hasNext();){
System.out.println(i1.next());
}
// remove() 移除当前指向的元素
i.remove();
// 增强for循环 for(集合/数组的类型 变量名:集合名/数组名){}
// 使用增强for循环遍历数组
int[] a = {1,2,3,4,5};
for(int i2: a){
System.out.println(i2);
}
2、Collection 线性集合
Collection是继承自Iterable的接口。
Collection下面有三个子接口:List(有序集合)、Set(无序集合) 、 Queue(线性列表)
List:有序集合、允许重复、有索引
Set:无序集合、不可重复、没索引
Collection中包含的方法:
方法 | 用途 |
---|---|
boolean add(Object o) | 增(单个) |
boolean remove(Object o) | 删(单个) |
void clear() | 删(清空) |
boolean contains(Object o) | 查(单个) |
boolean containsAll(Collection c) | 查找集合中是否有集合c中的元素 |
int size() | 返回元素的数量 |
boolean isEmpty() | 判断集合是否为空 |
Iterator iterator() | 返回一个迭代器 |
boolean addAll(Collection c) | 将集合c中所有的元素添加给该集合 |
void removeAll(Collection c) | 从集合中删除c集合中也有的元素 |
void retainAll(Collection c) | 从集合中删除集合c中不包含的元素 |
Collection<String> c1 = new ArrayList<>(); // 向上转型
Collection<String> c2 = new ArrayList<>();
c2.add("a"); // 增
c2.add("b");
c1.addAll(c2); // 增(多个)
int i = c1.size(); // 返回个数
c1.remove("a"); // 删
String s = c1.toString(); // 序列化
Object[] o = c1.toArray(); // 转为数组
c1.clear(); // 清空集合里面的内容
2.1、List 有序集合
List :先进先出、有序集合、允许重复、有索引
LIst接口里面包含的方法:
- add(索引,“元素”) ,返回空
- get(索引),返回获取的元素
- remove(索引),返回被移除元素
- set(索引,“替换后的元素”),返回被替换元素
注意索引越界异常
List接口常用实现类:ArrayList、LinkedList、Vector
2.1.1、ArrayList 可变长度数组(异步)
ArrayList 接口大小可变的数组(特点:查询快、增删慢、异步实现)
它的底层就是一个数组。增加一个元素:原理就是先填加一个数组(长度是原数组长度+1),然后把原来的数组拷贝过来。
关于ArrayList的操作见: https://blog.csdn.net/a__int__/article/details/113269683
2.1.2、LinkedList 链表
它的方法:
增:
add(E e):在链表后添加一个元素; 通用方法
addFirst(E e):在链表头部插入一个元素; 特有方法
addLast(E e):在链表尾部添加一个元素; 特有方法
push(E e):与addFirst方法一致
offer(E e):在链表尾部插入一个元素 add(int index, E element):在指定位置插入一个元素。
offerFirst(E e):JDK1.6版本之后,在头部添加; 特有方法 offerLast(E e):JDK1.6版本之后,在尾部添加; 特有方法
删除:
remove() :移除链表中第一个元素; 通用方法
remove(E e):移除指定元素; 通用方法
removeFirst(E e):删除头,获取元素并删除; 特有方法
removeLast(E e):删除尾; 特有方法
pollFirst():删除头; 特有方法
pollLast():删除尾; 特有方法
pop():和removeFirst方法一致,删除头。
poll():查询并移除第一个元素 特有方法
查:
get(int index):按照下标获取元素; 通用方法
getFirst():获取第一个元素; 特有方法
getLast():获取最后一个元素; 特有方法
peek():获取第一个元素,但是不移除; 特有方法
peekFirst():获取第一个元素,但是不移除;
peekLast():获取最后一个元素,但是不移除;
pollFirst():查询并删除头; 特有方法
pollLast():删除尾; 特有方法
poll():查询并移除第一个元素 特有方法
常用的方法:
push(E e):在链表头部插入一个元素
pop(): 获取头元素并删除,头结点为空抛出异常
poll(): 获取头元素并删除,头结点为空返回null
addLast(E e):在链表尾部添加一个元素;
pollLast():删除尾;
// LinkedList是list集合的一个链表实现(特点:查询慢、增删快)
// 如果a、b、c按顺序分别存入ArrayList、LinkedList,那么他们的答应结果分别是[a, b, c]、[c, b, a]
public static void main(String[] args) {
LinkedList<String> l = new LinkedList<>();
// 添加
l.add("a"); // 往尾部加
l.push("b"); // 往头部加
l.addFirst("c"); // 往头部加
// 获取
l.getFirst(); // 获取第一个
l.getLast(); // 获取最后一个
l.get(0); // 获取索引为0的
// 删除
l.pop(); // 删除头元素
l.poll(); // 删除头元素
l.pollLast(); // 删除尾元素
boolean e = l.isEmpty(); // 判断是否为空
l.clear(); // 清空
}
2.1.3、Vector 可变长度数组(同步)
Vector 同步的可变长度数组,现在基本上被ArrayList取代了
2.2、Set 无序集合
set继承自Collection,元素不可重复,没有索引,不是同步的
Set<Integer> hs = new HashSet<>();
hs.add(1);
hs.add(2);
hs.add(3);
// while遍历
Iterator<Integer> i = hs.iterator();
while (i.hasNext()){
System.out.println(i.next());
}
// for遍历
for(Integer i1:hs){
System.out.println(i1);
}
2.2.1、HashSet
class MyHashSet{
public static void main(String[] args) {
// 哈希值
// Object 超类中有一个方法hashCode(),可以获取一个对象的哈希值
Object t = new Test(1);
System.out.println(t.hashCode());
// String 字符串重写了这个方法
String s = new String("abc");
System.out.println(s.hashCode()); // 96354 字符串的内容相同,哈希值相同
System.out.println("abc".hashCode()); // 96354
System.out.println("重地".hashCode() == "通话".hashCode()); // 返回true,他两的哈希值相同,这是个巧合
// hash表:查询速度快
// jdk 1.8 之前: 哈希表=数组+链表
// jdk 1.8 之后: 哈希表=数组+链表 或 数组+红黑树 (当链表长度超过8位时,由链表转为红黑树)
// HashSet存储数据的过程:1、计算hashcode,判断这个哈希值是否存在。 2、用equals判断内容是否相等。
// 什么时候会把值存进去: ①当1为false,就把值存进去。 ②若1为true,2为false也存进去
String s1 = new String("abc");
String s2 = new String("abc");
HashSet<String> s3 = new HashSet<>();
s3.add(s1);
s3.add(s2);
s3.add("重地");
s3.add("通话");
System.out.println(s3); // 输出结果:[重地, 通话, abc]
// 自定义类重写hashCode()
// 重写前,两个自定义类对象,即使里面的属性值相同,两个对象都可以加入到HashSet中
// 重写后,两个自定义类对象,里面的属性值相同,两个对象加入到HashSet中,只保存一个
HashSet<Test> t1 = new HashSet<>();
Test t2 = new Test(11);
Test t3 = new Test(11);
t1.add(t2);
t1.add(t3);
System.out.println(t1); // 只存了一个 [Test{num=11}]
}
}
class Test{
// idea 里面按住alt+insert选择equals() and hashcode()可以重写这两个方法
private int num;
public Test(int num) {
this.num = num;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Test test = (Test) o;
return num == test.num;
}
@Override
public int hashCode() {
return Objects.hash(num);
}
@Override
public String toString() {
return "Test{" +
"num=" + num +
'}';
}
}
2.2.2 、LinkedHashSet
// LinkedHashSet相当于有序的HashSet (特点:有序、不重复)
// LinkedHashSet的底层是一个hash表+链表 (这条链表用来记录元素存储顺序)
LinkedHashSet<String> s = new LinkedHashSet<>();
s.add("q1");
s.add("q2");
s.add("q3");
System.out.println(s);
3、Collections 线性集合工具类
// Collections是集合的工具类
ArrayList<String> al = new ArrayList<>();
// 向集合里面添加多个元素
Collections.addAll(al,"123","abcd","aaa");
// 打乱集合顺序
Collections.shuffle(al);
// 按照升序排序 (只能传List,不能传set)
// List里面传自定义数据类型,只有实现了comparaTo方法的类型才能够排序(实现这个方法可以继承接口Comparable<自定义类型>)
// conpareTo方法返回值就是排序规则,按年龄升序例:return this.getAge()-person.getAge()
Collections.sort(al);
// 按照升序排序(在比较时重写排序规则)
Collections.sort(al, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// 按照字符串长度排序
// 这里return的负数就是升序、整数就是降序
return o1.length()-o2.length();
}
});
4、Map 键值对集合
Map是双列集合,一列存K,一列存V(键值对)。K不能重复
// Map是双列集合,一列存K,一列存V(键值对)。K不能重复
// Map的常用实现类:HashMap、LinkedHashMap(有序的Map)
// 常用方法
Map<String,String> m = new HashMap<>();
// 增, 返回插入的V
String v1 = m.put("医生", "张三");
// 改,返回修改之前的V
String v2 = m.put("医生", "李四"); // v2的值是“张三”
// 删,返回被删除的V
String v3 = m.remove("医生"); // v3的值是“李四”,如果填入的K没有,返回null
// 获取
String v4 = m.get("医生"); // 没有返回null
// 判断有否有某个K
boolean b1 = m.containsKey("医生");
// 遍历:通过键找值的方式
Map<Integer,String> m1 = new HashMap<>();
m1.put(1,"张三");
m1.put(2,"李四");
m1.put(3,"王五");
for (Integer mm:m1.keySet()){ // m1.keySet()返回的是一个set类型
System.out.println(m1.get(mm));
}
// 遍历:通过Entry对象遍历 (Entry:键值对对象,一个entry就是一个键和值)
// Entry 是Map的内部类
// Set<Map.Entry<Integer, String>> sme = m1.entrySet();
for(Map.Entry<Integer,String> e : m1.entrySet()){
System.out.println(e.getKey());
System.out.println(e.getValue());
}
4.1、 HashMap
// HashMap
// 常用方法,详细用法见上文
HashMap<String,String> m = new HashMap<>();
String v1 = m.put("医生", "张三");
4.2、LinkedHashMap
LinkedHashMap 有顺序的hashmap,它继承自HashMap
4.3、HashTable
特点:同步的、速度慢、K和V不可以为null
在jdk 1.2 之后被HashMap取代了
但是他的子类Properties依然在使用
Properties是唯一个和IO流结合的集合
5、JDK 9 集合中的of
JDK 9 集合对集合进行了优化 ,List、Set、Map接口里面添加了一个静态方法of,可以给集合一次性添加多个元素。
// 使用前提:集合中元素个数已经确定,不再改变
// 注意:1、of只适用于List、Set、Map接口,不适用于其实现类
// 2、of的返回值是一个不可改变的集合,不能再使用add、put等方法进行添加
// 3、不能有重复元素。
// List<String> l1 = List.of("a","b","c");
// Set<String> s1 = Set.of("a","b","c");
// Map<Integer,String> m1 = Map.of(1,"a",2,"b",3,"c");