一、Collection类
集合:Java中提供的一种容器,可以用来存储多个引用类型的数据。
集合与数组的区别:
- 数组的长度是固定的,而集合的长度是可变的。
- 集合存储的都是引用数据类型,若想存储基本数据类型需要存储对应的包装类。
1. 概述
1.1 简介
Collection:单列集合类的根接口,用于存储一些列符合某种规则的元素,其有两个常用的子接口:
-
java.util.List :元素存取有序、有索引、且可重复,主要的实现类: java.util.ArrayList 查询快、增删慢 java.util.LinkedList 查询慢、增删快 -
java.util.Set: 元素无索引、且不可重复,主要实现类: java.util.HashSet 存取无序 java.util.LinkedHashSet 存取有序 java.util.TreeSet 可以对集合中的元素进行排序
1.2 常用方法
Collection是所有单列集合的父接口,因此在Collection中定义了一些单列集合通用的方法,这些方法可用于操作所有单列集合。
public boolean add(E e); 把给定的对象添加到当前集合中 。
public void clear(); 清空集合中所有的元素。
public boolean remove(E e); 把给定的对象在当前集合中删除。
public boolean contains(Object obj); 判断当前集合中是否包含给定的对象。
public boolean isEmpty(); 判断当前集合是否为空。
public int size(); 返回集合中元素的个数。
public Object[] toArray(); 把集合中的元素,存储到数组中
2. 迭代器
2.1 使用
迭代:即Collection 集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
常用方法
public Iterator iterator();
public E next();
public boolean hasNext()
使用方式
当遍历集合时,首先通过调用t集合的iterator() 方法获得迭代器对象,然后使用hashNext() 方法判断集合中是否存在下一个元素,如果存在,则调用next() 方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。
常见问题
- 若集合中已无元素可迭代时,仍使用迭代器的
next() 方法,将会抛出java.util.NoSuchElementException 异常,若想重新迭代就需要重新获取一个新的迭代器。 - 在进行集合元素迭代时,若添加/移除集合中的元素,将导致无法继续迭代,抛出
ConcurrentModificationException 异常。
原理
iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素。
- 在调用
Iterator 的next() 方法之前,迭代器的索引位于第一个元素之前,不指向任何元素 - 当第一次调用迭代器的
next() 方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next() 方法时,迭代器的索引会指向第二个元素并将该元素返回 - 依此类推,直到
hasNext() 方法返回false ,表示到达了集合的末尾,终止对元素的遍历。
2.2 增强for循环
增强for循环专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作,否则会抛出ConcurrentModificationException 异常。
public class JavaTest {
public static void main(String[] args) {
Collection<String> strings = new ArrayList<String>();
strings.add("abc");
strings.add("cba");
strings.add("nba");
strings.add("def");
for (String str:strings) {
System.out.println(str);
}
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
if (strings.contains("nba")) {
strings.remove("nba");
}
}
}
}
二、Collections类
java.utils.Collections 是集合工具类,其成员方法都是静态方法,用来对collection 进行操作。
1. 排序
1.1 常用方法
public static void shuffle(List<?> list);
public static <T> void sort(List<T> list);
public static <T> void sort(List<T> list,Comparator<?superT>);
1.2 默认规则排序
- 在
collection 元素的类需要继承Compareable 接口,并重写compareTo() 方法。this - 参数 为升序,反之则为降序 - 创建
Collection 集合并添加要排序类的元素 - 调用
Collections.sort() 方法即可对Collection 中的元素排序
class Cls implements Comparable<Cls>{
private int age;
public Cls(int age) {
this.age = age;
}
@Override
public int compareTo(Cls c) {
return this.age - c.age;
}
@Override
public String toString() {
return age + " ";
}
}
public class JavaTest {
public static void main(String[] args) {
Cls c1 = new Cls(10);
Cls c2 = new Cls(20);
Cls c3 = new Cls(30);
Cls c4 = new Cls(40);
ArrayList<Cls> cls = new ArrayList<>();
cls.add(c1);
cls.add(c3);
cls.add(c4);
cls.add(c2);
Collections.sort(cls);
System.out.println(cls);
}
}
1.3 自定义规则排序
直接调用 Collections.sort() 方法,传入要排序的集合和Comparator 的匿名内部类(内部重写了compare() 方法)
class Cls{
public int age;
public Cls(int age) {
this.age = age;
}
}
public class JavaTest {
public static void main(String[] args) {
Cls c1 = new Cls(10);
Cls c2 = new Cls(20);
Cls c3 = new Cls(30);
Cls c4 = new Cls(40);
ArrayList<Cls> cls = new ArrayList<>();
cls.add(c1);
cls.add(c3);
cls.add(c4);
cls.add(c2);
Collections.sort(cls, new Comparator<Cls>() {
@Override
public int compare(Cls o1, Cls o2) {
return o2.getAge() - o1.getAge();
}
});
}
}
2. 可变参数
作用:在JDK1.5之后,如果定义一个方法需要接收多个同类型参数,可以使用可变参数进行简化,当传入多个参数时,相当于传入了一个数组。
- 一个方法只能有一个可变参数
- 如果方法中有多个参数,可变参数要放到最后。
class Cls{
public String name;
public void method(int age, String... name) {
for (String str:name) {
System.out.println(str);
}
}
}
public class JavaTest {
public static void main(String[] args) {
Cls cls = new Cls();
cls.method(10, "a", "b", "c");
ArrayList<String> strings = new ArrayList<>();
Collections.addAll(strings, "a", "b", "c");
}
}
三、List接口
1. 概述
特点
java.util.List 接口继承自Collection 接口,是单列集合的一个重要分支,习惯性地会将实现了List 接口的对象称为List集合。元素特点是存取有序、带有索引、可重复。
常用方法
List 作为Collection 集合的子接口,不但继承了Collection 接口中的全部方法,还增加了一些独有的方法。
public void add(int index, E element);
public E get(int index);
public E remove(int index);
public E set(int index, E element);
2. ArrayList集合
java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList 是最常用的集合。
常用方法
其内部没有独特的方法,都是实现的Collection 接口和List 接口的方法
ArrayList();
ArrayList<E> list1 = new ArrayList<E>();
public boolean add(E e);
public void add(int index,E element);
public boolean remove(Object o);
public E remove(int index);
public E set(int index, E element);
public E get(int index);
public int size();
3. LinkedList集合
java.util.LinkedList 集合数据存储的结构是双向链表。方便元素添加、删除的集合。
常用方法
实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。
public void addFirst(E e);
public void addLast(E e);
public E getFirst();
public E getLast();
public E removeFirst();
public E removeLast();
public E pop();
public void push(E e);
四、Set接口
1. 概述
Set接口:也称Set集合,但凡是实现了Set接口的类都叫做Set集合,特点是元素无索引、不可重复(唯一)
- Set集合没有特殊的方法,都是使用Collection接口的方法
- Set集合没有索引,所以遍历元素的方式就只有: 增强for循环,或者迭代器
2. HashSet集合
2.1 原理
底层数据结构
-
HashSet 集合存储数据的结构是哈希表
- JDK1.8之前哈希表底层采用数组+链表实现,同一哈希值的链表都存储在一个数组中,但当前链表的元素过多时,通过key遍历查找效率较低
- JDK1.8及之后哈希表底层采用数组+链表+红黑树,当链表元素长度超过8时,链表会转为红黑树,提高了遍历效率。
-
HashSet 集合保证元素唯一时依赖于hashCode() 和equals() 方法
- 当存储元素时
HashSet 会调用该元素的hashCode() 方法计算其哈希值 - 判断数组中该哈希值对应的位置上是否有元素,若没有则直接存储;
- 若有对应位置上有元素则说明产生了哈希冲突,会调用该元素的
equals() 方法与对应位置上的元素逐一比较 - 若该位置上有任意元素与该元素相同则不存储,若没有相同则在当前位置的链表/红黑树上添加一个新节点。
源码
HashSet 底层是HashMap
public class HashSet<E> extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable{
private transient HashMap<E,Object> map;
public HashSet() {
map = new HashMap<>();
}
}
2.2 存储自定义类
-
重写写该类的hashCode() 和equals() 方法。 由于HashSet 保证元素唯一性是通过hashCode() 根据元素地址生成的哈希值和equals() 比较元素的地址,因此在存储自定义类的元素时,需要重写该类的hashCode() 和equals() 方法。 public class Person{
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@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 &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
-
使用方法
class CA {
private String name;
private int age;
public CA(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CA ca = (CA) o;
return age == ca.age &&
Objects.equals(name, ca.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return name + ": " + age;
}
}
public class JavaTest {
public static void main(String[] args) {
CA ca0 = new CA("abc", 10);a
CA ca1 = new CA("123", 11);
CA ca2 = new CA("abe", 12);
CA ca3 = new CA("abc", 10);
HashSet<CA> cas = new HashSet<>();
cas.add(ca0);
cas.add(ca1);
cas.add(ca2);
cas.add(ca3);
for (CA ca: cas) {
System.out.println(ca.toString());
}
}
}
3. LinkedHashSet集合
**作用:**在HashSet 下面的子类java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构,可以解决HashSet 存取无序。
public class Test {
public static void main(String[] args) {
LinkedHashSet<Integer> set = new LinkedHashSet<>();
set.add(300);
set.add(100);
set.add(200);
set.add(500);
set.add(400);
set.add(400);
System.out.println(set);
}
}
4. TreeSet集合
TreeSet 集合是Set 接口的一个实现类,底层依赖于TreeMap ,是一种基于红黑树的实现,使用元素的自然新婚徐对元素进行排序,或者根据创建TreeSet 时提供的 Comparator 比较器进行排序,具体取决于使用的构造方法:
public TreeSet();
public TreeSet(Comparator<E> comparator);
class Cls{
public int age;
}
public class JavaTest {
public static void main(String[] args) {
TreeSet<Cls> cls1 = new TreeSet<>(new Comparator<Cls>() {
@Override
public int compare(Cls o1, Cls o2) {
return o1.age - o2.age;
}
});
}
}
五、Map集合
1. 特点
Map<K,V> 集合的特点: K用来限制键的类型,V用来限制值的类型
Map 集合存储元素是以键值对的形式存储,每一个键值对都有键和值Map 集合的键是唯一,值可以重复,如果键重复了,那么值就会被覆盖
Map集合子类: - HashMap<K,V> :存储数据采用的哈希表结构,元素的存取无序。 由于要保证键的唯一、不重复,需要重写键的hashCode() 方法、equals() 方法。
LinkedHashMap<K,V> :HashMap 下的子类,存储数据采用的哈希表结构+链表结构,元素存取有序。 通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode() 方法、equals() 方法。TreeMap<K,V> :TreeMap 集合和Map 相比没有特有的功能,底层的数据结构是红黑树; 可以对元素的键进行排序,排序方式有两种:自然排序和比较器排序
具体的使用方法可以参考Set集合子类的方法
2. 常用方法
public V put(K key, V value);
public V remove(Object key);
public V get(Object key);
public boolean containsKey(Object key);
public Set<K> keySet();
public Set<Map.Entry<K,V>> entrySet();
3. 遍历
遍历可以通过键找值的方式,也可以通过键值对的方式
public class JavaTest {
public static void main(String[] args) {
Map<String, Integer> stringIntegerMap = new HashMap<>();
stringIntegerMap.put("abc", 1);
stringIntegerMap.put("abd", 2);
stringIntegerMap.put("abe", 3);
stringIntegerMap.put("abf", 4);
Set<String> strings = stringIntegerMap.keySet();
for (String string:strings) {
System.out.println(string + " " + stringIntegerMap.get(string));
}
Set<Map.Entry<String, Integer>> entries = stringIntegerMap.entrySet();
for (Map.Entry<String, Integer> entrie : entries) {
System.out.println(entrie.getKey() +" "+ entrie.getValue());
}
}
}
rMap.put(“abe”, 3); stringIntegerMap.put(“abf”, 4);
//通过键找值
Set<String> strings = stringIntegerMap.keySet();
for (String string:strings) {
System.out.println(string + " " + stringIntegerMap.get(string));
}
//直接获取键值对
Set<Map.Entry<String, Integer>> entries = stringIntegerMap.entrySet();
for (Map.Entry<String, Integer> entrie : entries) {
System.out.println(entrie.getKey() +" "+ entrie.getValue());
}
}
}
|