文章目录
1. 集合分类
2. 没有使用泛型的集合
public static void main(String[] args) {
ArrayList strs=new ArrayList<>();
strs.add("123");
strs.add("145");
strs.add(789);
for(Object o:strs){
String s=(String)o;
System.out.println(s.indexOf("1"));
}
}
上面代码在本来是要添加字符串类型的,但是不小心添加了一个整数,这样当后面强转为字符串类型时就会报错
3. 使用泛型的集合
public static void main(String[] args) {
ArrayList<String> strs=new ArrayList<>();
strs.add("123");
strs.add("145");
// strs.add(789);//编译报错 不能添加整型
for(String s:strs){
System.out.println(s.indexOf("1"));
}
}
通过使用泛型,就可以在编译期防止将错误类型的对象放置到集合中
4. 一次性添加多个元素
public static void main(String[] args) {
Collection<Integer> collection = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Integer[] moreInts = {
6, 7, 8, 9, 10 };
collection.addAll(Arrays.asList(moreInts));
// Runs significantly faster, but you can't
// construct a Collection this way:
Collections.addAll(collection, 11, 12, 13, 14, 15);
Collections.addAll(collection, moreInts);
// Produces a list "backed by" an array:
List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);
list.set(1, 99); // OK -- modify an element
// list.add(21); // Runtime error; the underlying
// array cannot be resized.
}
Collection是一个接口, Collections一个工具类,可以对Collection类的对象进行多种操作
Arrays.asList() 的输出作为一个 List ,但是这里的底层实现是数组,没法调整大小。如果尝试在这个List 上调用 add() 或 remove(),由于这两个方法会尝试修改数组大小,所以会在运行时得到 “Unsupported Operation(不支持的操作)” 错误
5. Collection接口中的方法
通用方法,只有某个类实现了 Collection接口,比如ArrayList和LinkedList
- 添加: add(Object obj) addAll(Collection coll)
- 获取有效元素的个数: int size()
- 清空集合:void clear()
- 是否是空集合: boolean isEmpty()
- 是否包含某个元素:boolean contains(Object obj):是通过元素的equals方法来判断是否是同一个对象
- 是否包含某些元素:boolean containsAll(Collection c):也是调用元素的equals方法来比较的。拿两个集合的元素挨个比较
- 删除单个元素:boolean remove(Object obj) :通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素
- 删除一些元素:boolean removeAll(Collection coll)
- 取两个集合的交集:boolean retainAll(Collection c):把交集的结果存在当前集合中,不影响c
- 集合是否相等: boolean equals(Object obj)
- 转成对象数组: Object[] toArray()
- 获取集合对象的哈希值: hashCode()
- 遍历: 返回迭代器对象,用于集合遍历
6. 迭代器
迭代器是一个对象,它在一个序列中移动并选择该序列中的每个对象,而客户端程序员不知道或不关心该序列的底层结构
迭代器的作用:
- 使用 iterator() 方法要求集合返回一个 Iterator。Iterator 将准备好返回序列中的第一个元素
- 使用 next() 方法获得序列中的下一个元素
- 使用 hasNext() 方法检查序列中是否还有元素(最开始指针指向第一个元素的前一个位置)
- 使用 remove() 方法将迭代器最近返回的那个元素删除
在使用迭代器时不能调用集合的添加或删除方法:
可以使用迭代器自身的删除方法:
public static void main(String[] args) {
ArrayList<Integer> list=new ArrayList<>();
list.addAll(Arrays.asList(1,2,3,4,5));
Iterator<Integer> it=list.iterator();
while(it.hasNext()){
System.out.println(it.next());
it.remove();
}
System.out.println(list);//[]
}
如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,再调用remove都会报IllegalStateException 也就是说上面代码中的remove调用需要在next方法调用之后
for-each迭代
遍历集合的底层调用Iterator完成操作, 注意使用forEach迭代的同时改变引用变量是不影响原集合的
public static void main(String[] args) {
String[] strs=new String[3];
for(String s:strs){
s="123";
}
System.out.println(Arrays.toString(strs));//[null, null, null]
}
7. 列表List
List 承诺将元素保存在特定的序列中。List 接口在 Collection 的基础上添加了许多方法,允许在 List 的中间插入和删除元素
- ArrayList ,擅长随机访问元素,但在 List 中间插入和删除元素时速度较慢
- LinkedList ,它通过代价较低的在 List 中间进行的插入和删除操作,提供了优化的顺序访问。LinkedList 对于随机访问来说相对较慢,但它具有比 ArrayList更大的特征集
List除了从Collection集合继承的方法外,List 集合里添加了一些根据索引来,操作集合元素的方法
List接口中的方法:
- void add(int index, Object ele):在index位置插入ele元素
- boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
- Object get(int index):获取指定index位置的元素
- int indexOf(Object obj):返回obj在集合中首次出现的位置
- int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
- Object remove(int index):移除指定index位置的元素,并返回此元素
- Object set(int index, Object ele):设置指定index位置的元素为ele
- List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
LinkedList常用方法:
- getFirst() 和 element() 是相同的,它们都返回列表的头部(第一个元素)而并不删除它,如果 List 为空,则抛出 NoSuchElementException 异常。peek()方法与这两个方法只是稍有差异,它在列表为空时返回 null
- removeFirst() 和 remove() 也是相同的,它们删除并返回列表的头部元素,并在列表为空时抛出 NoSuchElementException 异常。poll() 稍有差异,它在列表为空时返回 null
- addFirst() 在列表的开头插入一个元素
- offer() 与 add() 和 addLast() 相同。它们都在列表的尾部(末尾)添加一个元素
- removeLast() 删除并返回列表的最后一个元素
使用LinkedList模拟栈: :
- 入栈:addFirst(x);
- 出栈:removeFirst();
- 取栈顶元素: getFirst();
使用LinkedList模拟队列: :
- 入队:addLast(x);
- 出队:removeFirst();
- 取队首元素: getFirst();
使用LinkedList模拟双端队列: :
- 队尾添加:addLast(x);
- 队首添加:addFirst(x);
- 队首出队:removeFirst();
- 队尾出队:removeLast() ;
- 取队首元素: getFirst()
- 取队尾元素: getLast()
8. 栈
Java 1.0 中附带了一个 Stack 类,结果设计得很糟糕(为了向后兼容,我们永远坚持 Java 中的旧设计错误)。Java 6 添加了 ArrayDeque ,其中包含直接实现堆栈功能的方法。
public static void main(String[] args) {
Deque<Integer> stack=new ArrayDeque<>();
stack.push(1);
stack.push(2);
stack.push(3);
stack.pop();
System.out.println(stack.peek());
}
9. 集合Set
Set 不保存重复的元素。如果试图将相同对象的多个实例添加到 Set 中,那么它会阻止这种重复行为。
Set 具有与 Collection 相同的接口,因此没有任何额外的功能,不像前面两种不同类型的 List 那样。实际上,Set 就是一个 Collection ,只是行为不同
9.1 HashSet
- 不能保证元素的排列顺序
- HashSet 不是线程安全的
- 集合元素可以是 null
- HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等
- 对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”
HashSet的添加过程:
- 计算添加进来的对象的hash值,根据hash值进行映射,映射到某个位置(该位置上可以有多个元素,多个元素以链表形式连接)
- 如果某个元素的hash值对应的位置上面已经有元素,则遍历链表比较,如果遇到一个元素使用equals比较相同,添加失败;找不到相同的,添加成功。
重写 hashCode() 方法的基本原则:
- 在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值
- 当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode()方法的返回值也应相等
- 对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值
9.2 LinkedHashSet
- LinkedHashSet 是 HashSet 的子类
- LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的
- LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能
- LinkedHashSet 不允许集合元素重复
9.3 TreeSet
- TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态
- TreeSet底层使用红黑树结构存储数据
- 添加到TreeSet接口中的元素要么实现了Comparable接口,要么实现了Compartor接口
class Student implements Comparable<Student>{
String name;
int score;
public Student(String name,int score){
this.name=name;
this.score=score;
}
@Override
public int compareTo(Student stu) {
// TODO Auto-generated method stub
return this.score-stu.score;//按分数升序
}
public String toString(){
return "name: "+name+" score: "+score;
}
}
public class Drawing {
public static void main(String[] args) {
TreeSet<Student> stus=new TreeSet<>();
stus.add(new Student("Tom",97));
stus.add(new Student("Bob",95));
stus.add(new Student("Mary",93));
System.out.println(stus);
}
}
class Student{
String name;
int score;
public Student(String name,int score){
this.name=name;
this.score=score;
}
public String toString(){
return "name: "+name+" score: "+score;
}
}
public class Drawing {
public static void main(String[] args) {
TreeSet<Student> stus=new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// TODO Auto-generated method stub
return o2.score-o1.score;//按分数降序
}
});
stus.add(new Student("Tom",97));
stus.add(new Student("Bob",95));
stus.add(new Student("Mary",93));
System.out.println(stus);
}
}
当同时实现了两个接口时,Comparator接口的优先级较高
10. Map接口
- Map与Collection并列存在。用于保存具有映射关系的数据:key-value
- Map 中的 key 和 value 都可以是任何引用类型的数据
- Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法
- 常用String类作为Map的“键“
常用方法:
- Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
- void putAll(Map m):将m中的所有key-value对存放到当前map中
- Object remove(Object key):移除指定key的key-value对,并返回value
- void clear():清空当前map中的所有数据
- Object get(Object key):获取指定key对应的value
- boolean containsKey(Object key):是否包含指定的key
- boolean containsValue(Object value):是否包含指定的value
- int size():返回map中key-value对的个数
- boolean isEmpty():判断当前map是否为空
- boolean equals(Object obj):判断当前map和参数对象obj是否相等
- Set keySet():返回所有key构成的Set集合
- Collection values():返回所有value构成的Collection集合
- Set entrySet():返回所有key-value对构成的Set集合
10.1 HashMap
- HashMap是 Map 接口使用频率最高的实现类
- 允许使用null键和null值,与HashSet一样,不保证映射的顺序
- 所有的key构成的集合是Set:无序的、不可重复的。所以,key所在的类要重写:equals()和hashCode()
- 所有的value构成的集合是Collection:无序的、可以重复的。所以,value所在的类要重写:equals()
- 一个key-value构成一个entry
- 所有的entry构成的集合是Set:无序的、不可重复的
- HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等
- HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true
public static void main(String[] args) {
HashMap<String,Integer> map=new HashMap<>();
map.put("A", 65);
map.put("B", 66);
map.put("C", 67);
//遍历key
for(String key:map.keySet()){
System.out.println("key: "+key);
}
//遍历value
for(Integer value:map.values()){
System.out.println("value: "+value);
}
//遍历key和value
for(Entry<String,Integer> entry:map.entrySet()){
System.out.println("key: "+entry.getKey()+" value:"+entry.getValue());
}
}
10.2 LinkedHashMap
- LinkedHashMap 是 HashMap 的子类
- 在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序
- 与LinkedHashSet类似,LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致
10.3 TreeMap
- TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态
- TreeSet底层使用红黑树结构存储数据
- 和TreeSet一样,TreeMap需要实现Comparable接口或Comparator接口之一
- 如果两个key是两个不同的对象,只要这两个对象的比较的结果相同(不是地址比较),就认为是一个key
11. Collections类中的常用方法
Collections 是一个操作 Set、List 和 Map 等集合的工具类
均为static方法
- reverse(List):反转 List 中元素的顺序
- shuffle(List):对 List 集合元素进行随机排序
- sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
- sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
- swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
- Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
- Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
- Object min(Collection)
- Object min(Collection,Comparator)
- int frequency(Collection,Object):返回指定集合中指定元素的出现次数
- void copy(List dest,List src):将src中的内容复制到dest中
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List 对象的所有旧值