集合
一、集合框架图(简化)
二、Collection接口
Collection接口是处理对象集合的根接口,其中定义了很多对元素进行操作的方法。Collection接口有两个主要的子接口List和Set,注意:Map不是Collection的子接口
Collection常用的方法:
boolean add(Object o) | 向集合中添加一个元素 |
---|---|
boolean addAll(Collection o) | 向集合中o中的所有元素添加到该集合中 |
void clear() | 删除该集合中的所有元素 |
boolean remove ( Object o ) | 删除该集合中指定的元素 |
boolean removeAll ( Collection c ) | 删除该集合中包含指定集合 c 中的所有元素 |
boolean contains ( Object o ) | 判断该集合中是否包含某个元素 |
boolean containsAll ( Collection c ) | 判断该集合中是否包含指定集合 c 中的所有元素 |
Iterator iterator () | 返回在该集合的元素上进行迭代的迭代器( Iterator ),用于遍历该集合所有元素 |
int size () | 获取该集合元素个数 |
1.List接口
List接口继承于Collection接口,它可以定义一个允许重复的有序集合。因为List中的元素是有序的,所以我们可以通过使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。
(1)ArrayList
ArrayList 是 List 接口的一个实现类,它是程序中最常见的一种集合。在 ArrayList 内部封装了一个长度可变的数组对象,当存入的元素超过数组长度时, ArrayList 会在内存中分配一个更大的数组来存储这些元素,因此可以将 ArrayList 集合看作一个长度可变的数组。
正是由于 ArrayList 内部的数据存储结构是数组形式,在增加或删除指定位置的元素时,会创建新的数组,效率比较低,因此不适合做大量的增删操作。但是,这种数组结构允许程序通过索引的方式来访问元素,因此使用 ArrayList 集合在遍历和查找元素时显得非常高效。
(2)LinkedList
ArrayList 集合在查询元素时速度很快,但在增删元素时效率较低,为了克服这种局限性,可以使用 List 接口的另一个实现类 LinkedList 。该集合内部包含有两个 Node 类型的 first 和 last 属性维护一个双向循环链表,链表中的每一个元素都使用引用的方式来记住它的前一个元素和后一个元素,从而可以将所有的元素彼此连接起来。当插入一个新元素时,只需要修改元素之间的这种引用关系即可,删除一个节点也是如此。正因为这样的存储结构,所以 LinkedList 集合对于元素的增删操作表现出很高的效率。
2.Collection集合遍历
(1)Iterator遍历集合
当遍历元素时,首先通过调用 ArrayList 集合的 iterator ()方法获得迭代器对象,然后使用 hasNext ()方法判断集合中是否存在下一个元素,如果存在,则调用 next ()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。需要注意的是,在通过 next ()方法获取元素时,必须保证要获取的元素存在,否则,会抛出 NoSuchElementException 异常。
示例代码:
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("Hang");
System.out.println("-------迭代器-------");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
输出结果:
-------迭代器-------
Hello
World
Hang
(2)foreach遍历集合
虽然 Iterator 可以用来遍历集合中的元素,但写法上比较烦琐,为了简化书写,从 JDK 5开始,提供了 foreach 循环。 foreach 循环是一种更加简洁的 for 循环,也称增强 for 循环。 foreach 循环用于遍历数组或集合中的元素,其具体语法格式如下:
for(容器中的元素类型 临时变量:容器变量){
//执行语句
}
示例代码:
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("Hang");
System.out.println("-------For-Each-------");
for (String string : list) {
System.out.println(string);
}
}
}
输出结果:
-------For-Each-------
Hello
World
Hang
在JDK8中,根据Lambda表达式特性ha还增加了一个forEach(方法来遍历集合,该方法所需要的参数是一个函数式接口。接下来通过一个案例来演示遍历集合对象:
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("Hang");
System.out.println("-------For-Each-------");
list.forEach(obj -> System.out.println(obj));
}
}
输出结果:
-------For-Each-------
Hello
World
Hang
(3)普通for循环遍历集合
foreach循环虽然书写起来很简洁,但在使用时也存在一定的局限性。当使用 foreach 循环遍历集合和数组时,只能访问集合中的元素,不能对其中的元素进行修改。而这时普通for就发挥作用了,具体代码如下:
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("Hang");
System.out.println("-------普通for循环-------");
String[] strArray = new String[list.size()];
list.toArray(strArray);
for (int i = 0; i < strArray.length; i++) {
strArray[2] = "aaa";
System.out.println(strArray[i]);
}
}
}
输出结果:
-------普通for循环-------
Hello
World
aaa
3.Set接口
Set是一种不包括重复元素的Collection。它维持它自己的内部排序,所以随机访问没有任何意义。与List一样,它同样允许null的存在但是仅有一个。由于Set接口的特殊性,所有传入Set集合中的元素都必须不同,同时要注意任何可变对象,如果在对集合中元素进行操作时,导致e1.equals(e2)==true,则必定会产生某些问题。Set接口有三个具体实现类,分别是散列集HashSet、链式散列集LinkedHashSet和树形集TreeSet。
(1)HashSet集合
HashSet 是一个没有重复元素的集合。它是由HashMap实现的,不保证元素的顺序(这里所说的没有顺序是指:元素插入的顺序与输出的顺序不一致),而且HashSet允许使用null 元素,HashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。
HashSet使用和理解中容易出现的误区:
a.HashSet中存放null值
HashSet中是允许存入null值的,但是在HashSet中仅仅能够存入一个null值。
b.HashSet中存储元素的位置是固定的
HashSet中存储的元素的是无序的,这个没什么好说的,但是由于HashSet底层是基于Hash算法实现的,使用了hashcode,所以HashSet中相应的元素的位置是固定的。
(2)TreeSet
TreeSet是一个有序集合,其底层是基于TreeMap实现的,非线程安全。TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。当我们构造TreeSet时,若使用不带参数的构造函数,则TreeSet的使用自然比较器;若用户需要使用自定义的比较器,则需要使用带比较器的参数。
注意:TreeSet集合不是通过hashcode和equals函数来比较元素的.它是通过compare或者comparaeTo函数来判断元素是否相等.compare函数通过判断两个对象的id,相同的id判断为重复元素,不会被加入到集合中。
4.Map接口
Map与List、Set接口不同,它是由一系列键值对组成的集合,提供了key到Value的映射。同时它也没有继承Collection。在Map中它保证了key与value之间的一一对应关系。也就是说一个key对应一个value,所以它不能存在相同的key值,当然value值可以相同。
(1)HashMap
以哈希表数据结构实现,查找对象时通过哈希函数计算其位置,它是为快速查询而设计的,其内部定义了一个hash表数组(Entry[] table),元素会通过哈希转换函数将元素的哈希地址转换成数组中存放的索引,如果有冲突,则使用散列链表的形式将所有相同哈希地址的元素串起来,可能通过查看HashMap.Entry的源码它是一个单链表结构。
(2)TreeMap
在Java 中,Map接口还有一个常用的实现类TreeMap,它也是用来存储键值映射关系的,并且不允许出现重复的键。在 TreeMap 内部是通过二叉树的原理来保证键的唯一性,这与 TreeSet 集合存储的原理一样,因此 Tree Map中所有的键是按照某种顺序排列的,一种是自然排序,一种是定制排序,具体取决于使用的构造方法。
自然排序:TreeMap中所有的key必须实现Comparable接口,并且所有的key都应该是同一个类的对象,否则会报ClassCastException异常。
定制排序:定义TreeMap时,创建一个comparator对象,该对象对所有的treeMap中所有的key值进行排序,采用定制排序的时候不需要TreeMap中所有的key必须实现Comparable接口。
TreeMap判断两个元素相等的标准:两个key通过compareTo()方法返回0,则认为这两个key相等。
如果使用自定义的类来作为TreeMap中的key值,且想让TreeMap能够良好的工作,则必须重写自定义类中的equals()方法,TreeMap中判断相等的标准是:两个key通过equals()方法返回为true,并且通过compareTo()方法比较应该返回为0。
三、泛型
- 本质是参数化类型,把类型作为参数传递
- 常见形式有泛型类、泛型接口、泛型方法
- 语法 T成为类型占位符,表示一种引用类型,可以写多个逗号隔开
- 好处 1. 提高代码重用性 2. 防止类型转换异常,提高代码安全性
四、总结
1、什么是集合?
在java.util.*;下的一种用来储存对象的容器
和数组的区别:
(1) 数组长度固定,集合长度不固定
(2) 数组可以存储基本类型和引用类型,集合只能存储引用类型
2.Collection接口
特点:无序、无下标、不可重复
创建集合
Collection collection = new ArrayList();
3.常用方法
(1)添加元素
collection.add();
(2)删除元素
collection.remove();
collection.clear();
4.遍历元素
(1)增强for
for(Object object : collection){ }
(2)For-Each
list.forEach(obj -> System.out.println(obj));
(3)迭代器
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
5.判断
collection.contains();
collection.isEmpty();
List集合
特点:有序、有下标、元素可重复
创建集合
List list = new ArrayList<>( );
1.常用方法
(1)添加元素
list.add( );
(2)删除元素 可以用索引
list.remove(0);
(3)获取
list.indexOf( );
2.遍历
(1)使用普通for遍历
for(int i = 0; i < lise.size(); i++){
sout(list.get(i));
}
(2)使用增强for
for(Object list: collection){ }
(3)使用迭代器
Iterator it = collection.iterator();
while(it.hasNext()){
String object = (String)it.next();
}
ArrayList
特点:查询快、增删慢、运行效率快但线程不安全
创建集合
ArrayList arrayList = new ArrayList<>();
1.常用方法
(1)添加元素
arrayList.add();
(2)删除元素
arrayList.remove(new Student("name", 10));
(3)判断
arrayList.contains();
arrayList.isEmpty();
(4)查找
arrayList.indexof();
LinkedList
特点:增删快,查询慢
创建集合
LinkedList li = new LinkedList<>();
常用方法与List一致
Set集合
特点:无序、无下标、元素不可重复
方法:全部继承自Collection中的方法
增、删、遍历、判断与collection一致
HashSet
创建集合
HashSet<String> hashSet = new HashSet<String>();
1.常用方法
(1)添加元素
hashSet.add( );
(2)删除元素
hashSet.remove( );
2.遍历 1. 增强for 2. 迭代器
TreeSet
特点:
-
基于排列顺序实现元素不重复
-
实现SortedSet接口,对集合元素自动排序
-
元素对象的类型必须实现Comparable接口,指定排序规则
-
通过CompareTo方法确定是否为重复元素
创建集合
TreeSet<String> treeSet = new TreeSet<>()
1,常用方法
(1)添加元素
treeSet.add();
(2)删除元素
treeSet.remove();
2,遍历 1. 增强for 2. 迭代器
Map
特点:
- 用于存储任意键值对(key - value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
方法
- V put(K key, V value) 将对象存到集合中,关联键值
- Object get(Object key) 根据键获得对应的值
- Set
返回所有的Key - Collection
values() 返回包含所有值的Collection集合 - Set<Map.Entry<K, V>> 键值匹配的Set集合
HashMap
使用key可使hashcode和equals作为重复
增、删、遍历、判断与上述一致
TreeMap
实现了SortedMap接口(是map的子接口),可以对key自动排序
Collection工具类
概念:集合工具类,定义了除了存取以外的集合常用方法
直接二分查找
int i = Collections.binarySearch(list, x); 成功返回索引
其他方法 : copy复制、reverse反转、shuffle打乱
泛型
- 本质是参数化类型,把类型作为参数传递
- 常见形式有泛型类、泛型接口、泛型方法
- 语法 T成为类型占位符,表示一种引用类型,可以写多个逗号隔开
- 好处 1. 提高代码重用性 2. 防止类型转换异常,提高代码安全性