本文目录
1. List
继承自Collection
- 有序
- 带索引
- 可以存储重复元素
常用方法:
boolean add(e)
返回是否添加成功void add(index, e)
boolean remove(e)
返回删除是否成功E remove(index)
返回删除之前index位置的元素E set(index, e)
返回更新之前的元素E get(index)
返回index位置的元素
2. ArrayList
不是同步的,如果多线程访问可能不安全。
- 查询快
- 增删慢
注意:当长度到达默认的长度后,再添加元素需要进行整个底层数组的复制,速度会慢,如果长度没到默认长度,那么插入就是O(1)。
3. LinkedList
不是同步的,如果多线程访问可能不安全。
- 双向链表。
- 包含大量操作首尾元素的方法。
常用方法:
-
void addFirst(E e)
:将指定元素插入此列表的开头,等效于push。 -
void push(E e)
:将元素推入此列表所表示的堆栈。 -
void addLast(E e)
:将指定元素添加到此列表的结尾,等效于add。
E getFirst()
:返回此列表的第一个元素。E getLast()
:返回此列表的最后一个元素。
-
E removeFirst()
:移除并返回此列表的第一个元素。等效于pop。 -
E pop()
:从此列表所表示的堆栈处弹出一个元素。 -
E removeLast()
:移除并返回此列表的最后一个元素。
boolean isEmpty()
:如果列表不包含元素,则返回true。
4. Vector
同步的,线程安全。
5. HashSet
实现了java.util.Set接口
- 不存储重复元素
- 没索引
- 不能使用普通的for循环
- 不保证按序存取
- 底层是哈希表(查询速度快)
5.1 使用
- 可以看出,存入顺序和实际存储的顺序并不一定相同。
package SetDemo;
import java.util.HashSet;
import java.util.Set;
public class HashSetDemo {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(3);
set.add(2);
set.add(3);
System.out.println(set);
}
}
//===========输出===========//
[1, 2, 3]
5.2 遍历
- 增强for循环。
- 迭代器,
set.iterator()
。
for (Integer integer : set) {
System.out.println(integer);
}
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
6. 哈希表原理
6.1 哈希值
-
由操作系统给出的一个十进制数字。对象的逻辑地址。
public native int hashCode();
-
String类的hashCode()重写了,输出的不是地址值。
“重地”与“通话”的哈希值相同,是个巧合。
6.2 哈希表
jdk1.8开始,哈希表变成了 数组+链表/红黑树(提高查询速度)。
- 用数组存储哈希值
- 链表用来解决哈希冲突
- 如果一个哈希值下面超过了8个元素,就会把链表转为红黑树。
6.3 Set存储不重复元素的原理
Set的add过程:
- 调用元素的hashCode方法和equals方法,判断元素是否重复。
- hashCode方法计算出哈希值
- 在数组中查找对应哈希值的元素
- 如果不存在,就插入。
- 如果存在,调用equals方法判断是否重复。
- 重复就不插入,不重复就插入
6.4 Set存储自定义类型元素
存储的元素必须重写hashCode和equals方法。
举例:定义一个Person类,要求姓名和年龄相同的人是同一个人。将对象存入HashSet。
//===========类定义===========//
package SetDemo;
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//重写equlas函数
//age相同且name相同,就认为是同一个人。
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
name.equals(person.name);
}
//重写toString函数
@Override
public String toString() {
return "[name='" + name + '\'' + ", age=" + age + "]";
}
//重写hashCode函数
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
//===========测试函数===========//
package SetDemo;
import java.util.HashSet;
import java.util.Set;
public class HashSet_Person {
public static void main(String[] args) {
Person p1 = new Person("a",18);
Person p2 = new Person("b",21);
Person p3 = new Person("c",18);
Person p4 = new Person("a",18);
//p1的哈希值应该与p4相同
System.out.println(p1.hashCode());
System.out.println(p2.hashCode());
System.out.println(p3.hashCode());
System.out.println(p4.hashCode());
Set<Person> personSet = new HashSet<>();
personSet.add(p1);
personSet.add(p2);
personSet.add(p3);
personSet.add(p4);
System.out.println(personSet);
}
}
//===========输出===========//
3986
4020
4048
3986
[[name='c', age=18], [name='a', age=18], [name='b', age=21]]
7. LinkedHashSet 插入有序集合
继承自HashSet
- 底层是哈希表+链表
- 插入有序
- 可索引
- 意味着add、remove等操作均可指定index。
package SetDemo;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class LinkedHashSetDemo {
public static void main(String[] args) {
Set<Integer> set1 = new LinkedHashSet<>();
Set<Integer> set2 = new HashSet<>();
set1.add(3);
set1.add(1);
set1.add(2);
set2.add(3);
set2.add(1);
set2.add(2);
System.out.println(set1);
System.out.println(set2);
}
}
//===========输出===========//
[3, 1, 2]
[1, 2, 3]
8. 可变参数(变长参数表)
public void fun(参数类型...形参名)
等价于
public void fun(参数类型[] 形参名)
-
参数表底层是一个数组
-
注意事项:
- 一个方法只能有一个变长参数。
- 如果参数表有变长参数有普通参数,变长参数必须写在参数表末尾。
public class test {
public static void main(String[] args) {
fun(1,2,3,4,5);
fun(1,2,3);
fun();
}
private static void fun(int...nums) {
int sum = 0;
for(int i:nums){
sum+=i;
}
System.out.println(sum);
}
}
//===========输出===========//
15
6
0
9. Collections工具类
9.1 shuffle
Collections.shuffle(List<T> l)
随机打乱集合内元素的顺序。
9.2 addAll
Collections.addAll(集合对象,T...elements)
, 往集合内添加多个元素。
9.3 sort
- 对集合进行排序,默认是升序排序。
- 只能对List排序,不能对set排序。
- 如果对自定义的类排序,就需要实现Comparable接口的compareTo方法来定义排序规则。
-
类内实现Comparable接口
- 重写comparaTo() 默认返回0,意思是所有元素都是相同的。
@Override public int compareTo(Person o) { //this-o,升序排列。 return this.age-o.age; }
-
使用Comparator,在sort函数内实现排序规则。
- 创建Comparator的匿名对象。
List<Integer> integers = new ArrayList<>(); Collections.addAll(integers, 5, 3, 6, 8, 23, 4, 7); System.out.println("排序前:" + integers); Collections.sort(integers, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2-o1; } }); System.out.println("排序后:"+integers);
//==========输出==========// 排序前:[5, 3, 6, 8, 23, 4, 7] 排序后:[23, 8, 7, 6, 5, 4, 3]
-
创建Comparator对象
前面减后面,就是升序排列
System.out.println("=========使用Comparator对象==========="); List<Integer> integerList = new ArrayList<>(); Collections.addAll(integerList, 5, 3, 6, 8, 23, 4, 7); Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }; Collections.sort(integerList, comparator); System.out.println("排序后:" + integerList);
//==========输出==========// 排序后:[23, 8, 7, 6, 5, 4, 3]
10. Map<K, V>
java.util.Map<K, V>
- 一个K只能映射到一个V上面。
- K和V的类型可以不同。
- K不允许重复,V可以重复。
10.1 HashMap
java.util.HashMap
- 基于哈希表实现。
- 不保证插入顺序
- 线程不安全,不同步
10.2 LinkedHashMap
java.util.LinkedHashMap
- 记录哈希表+链表实现
- 保证插入顺序
10.3 Map常用方法
V put(K, V)
往Map中插入元素。若K存在,则更新V,返回原来的V。K不存在,则插入键值对并返回空。V get(K)
获取K对应的值。V remove(K)
如果存在K,则移除此键值对,并返回被移除的V。不存在K则返回空。boolean remove(K, V)
按键值对移除元素,如果存在返回true,不存在返回false。- 注意:
- 如果V是Integer类型,返回值不要用int,因为可能返回null,此时如果自动拆箱,就会报空指针异常。
boolean containsKey(K)
是否存在K。boolean containsValue(V)
是否存在V。
-
Set<Map.Entry<K, V>> entrySet()
返回包含map中映射关系的Set视图。 -
Set<K> keySet()
返回包含map中的Key的Set视图。 -
Collection<V> values()
返回map中的values集合。 -
注意:
- 因为V可以重复,所以values()返回的是集合。
- 因为K不允许重复,所以keySet()返回的是Set。
isEmpty()
是否为空。
package MapDemo;
import java.util.HashMap;
import java.util.Map;
public class HashMapDemo {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(4,"d");
System.out.println("插入1 : " + map.put(1, "a"));
System.out.println("更新1,被替换的原来的V是: " + map.put(1, "ab"));
System.out.println("-------------------------");
System.out.println("获取存在的K : 1 - " + map.get(1));
System.out.println("获取不存在的K : 2 - " + map.get(2));
System.out.println("-------------------------");
System.out.println("移除不存在的K : 2 - " + map.remove(2));
System.out.println("移除存在的K : 1 - " + map.remove(1));
System.out.println("-------------------------");
System.out.println("按K-V移除不存在的2:b - " + map.remove(2,"b"));
System.out.println("按K-V移除不存在的4:b - " + map.remove(4,"b"));
System.out.println("按K-V移除存在的4:d - " + map.remove(4,"d"));
System.out.println("-------------------------");
System.out.println("map中的KV对:"+map);
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
System.out.println("包含map中映射关系的Set视图: " + entrySet);
Set<Integer> keySet = map.keySet();
System.out.println("包含map中的Key的Set视图" + keySet);
}
}
//==========输出==========//
插入1 : null
更新1,被替换的原来的V是: a
-------------------------
获取存在的K : 1 - ab
获取不存在的K : 2 - null
-------------------------
移除不存在的K : 2 - null
移除存在的K : 1 - ab
-------------------------
按K-V移除不存在的2:b - false
按K-V移除不存在的4:b - false
按K-V移除存在的4:d - true
-------------------------
map中的KV对:{}
map中的KV对:{1=a, 2=b, 3=c, 4=d}
包含map中映射关系的Set视图: [1=a, 2=b, 3=c, 4=d]
包含map中的Key的Set视图[1, 2, 3, 4]
10.4 Map的遍历
-
- 使用keySet方法,取出所有的K,存储在Set中。
- 遍历Set,通过map.get(K)来找到对应的值,实现遍历。
-
- 使用map.entrySet()方法获取entry对象的Set。
- 遍历Set,使用entry对象的getKey()或getValue()方法。
10.5 HashMap存储自定义类型
- 重写hashCode和equals方法,保证HashMap存储的内容是唯一的。
10.6 LinkedHashMap
继承自HashMap
-
实现了插入有序。
-
线程不安全。
-
特有方法:
boolean removeEldestEntry(Map.Entry<K,V> eldest)
- 用来移除最早的键值对。
- 移除成功,返回true。
11. HashTable
- 线程安全的。
- 不能存储null。
- JDK 1.2 以后被HashMap取代。
12. 通过List、Set、Map的静态方法来创建不可变对象
of(E…e)方法。
List.of()
Set.of()
Map.of()
- 从jdk1.9开始。
- 返回不可变对象。
- 接收变长参数。
- Set和Map接收参数时不能有重复元素。