文章目录
1、集合概述
集合和数组的区别:
- 长度不同
- 数组一旦初始化长度不能改变
- 集合是可以改变的
- 元素类型不同
- 数组既可以存储基本数据类型元素,也可以存储引用数据类型元素
- 集合只能存储引用数据类型元素=
集合的体系结构:
- 单列集合:Collection接口(单个)
- List接口(元素有序且可重复):ArrayList类、LinkedList类、Vector类
- Set接口(元素无序且不可重复):HashSet类、LinkedHashSet类、TreeSet类
- 多列集合:Map接口(KV键值对)
- HashMap类、LinkedHashMap类、TreeMap类、HashTable类、Properties类
1.1 Collection接口
- 特点:它是“单列集合”的顶级接口。
- 位置:java.util
- 方法:
-
boolean add(E e)
确保此 collection 包含指定的元素(可选操作)。
-
void clear()
移除此 collection 中的所有元素(可选操作)。
-
boolean contains(Object o)
如果此 collection 包含指定的元素,则返回 true。
-
boolean isEmpty()
如果此 collection 不包含元素,则返回 true。
-
Iterator iterator()
返回在此 collection 的元素上进行迭代的迭代器。
-
boolean remove(Object o)
从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
-
int size()
返回此 collection 中的元素数。
1.2 Collection集合的面试题
-
多态调用方法的特点:
先看父类或者父接口中是否含有这个方法,如果有执行子类或者实现类重写后的方法;如果没有编译报错
使用多态创建Collection实现类对象,在打印对象名时,其实就是隐式调用对象的toString(),既然如此,调用toString()也满足多态调用方法的特点,先看Collection接口中是否含有toString(),通过查看源码发现Collection接口及其父接口中并没有toString(),所以代码应该编译报错,但是实际上编译没有报错,而且这个多态形式的对象也可以显示调用toString(),为什么?
-
原因:
java中所有接口都隐式继承Object类的接口形式或者说Java中所有的接口里面都隐式包含Object类中实例方法的抽象形式
public class CollectionDemo03 {
public static void main(String[] args) {
//使用多态的方式创建Collection集合实现类对象
Collection coll = new ArrayList();
//添加元素
coll.add("abc");
coll.add("def");
coll.add("ghi");
System.out.println(coll.toString());
}
}
1.3 Iterator迭代器
- 格式:
Collection coll = new ArrayList();
Iterator it = coll.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
-
迭代器的注意事项:
- 使用迭代器进行迭代器集合时,只能迭代一次,如果想二次使用,需要重新获取迭代器对象
- 在使用迭代器的过程中,不能针对集合中的元素或者集合的长度做任何更改,否则会发生并发修改异常ConcurrentModificationException
1.4 增强for(JDK5.0)
-
原理:其实就是前面讲解的"迭代器"操作的简化版
-
格式:
for (集合元素的数据类型 对象名 : 容器名) { }
-
增强for的注意事项
-
在使用增强for的过程中,不能针对集合中的元素或者集合的长度做任何更改,否则会发生并发修改异常ConcurrentModificationException
-
增强for除了可以遍历集合,也可以遍历数组,但是在实际开发中不推荐使用增强for遍历数组
原因:
效率低,增强for的底层是迭代器,迭代器又是集合所特有,通过增强for遍历数组,是先将数组转换为集合,再由集合获取迭代器对象进行遍历。尤其是基本数据类型数组,是先将基本数据类型数组转换为存储对应包装类型的数组,再由存储包装类型的数组转换为存储包装类型的集合,通过集合获取迭代器对象进行遍历。
1.5 Stream流
public static void main(String[] args) {
Collection coll = new ArrayList();
//添加元素
coll.add("abc");
coll.add("def");
coll.add("ghi");
//获取流对象
Stream stream = coll.stream();
stream.forEach(System.out::println);
}
2、泛型
-
定义:未知的,没有确定的数据类型
-
声明格式
<未知数据类型的名>英文大写
-
声明内容
可以在声明类的时候进行声明泛型
可以在声明接口的时候进行声明泛型
可以在声明方法的时候进行声明泛型
-
好处
将程序逻辑处理提前到编译时期,可以通过泛型给集合指定存储类型,如果不是该类型的话,编译报错
2.1 含有泛型的类
-
声明格式:
public class 类名<泛型> { }
-
注意事项:
在使用含有泛型的类的时候,需要给该泛型进行确认,如果不明确,JVM明确为Object类型。
-
明确时机:
创建该类对象时
2.2 含有泛型的接口
-
声明格式:
public interface 接口名<泛型> { }
-
注意事项:
在使用含有泛型的接口的时候,需要给该泛型进行确认,如果不明确,JVM明确为Object类型
-
明确时机:
创建该接口的实现类对象时
2.3 含有泛型的方法
-
声明格式:
修饰符 <泛型> 返回值类型 方法名 () {}
-
注意事项:
在使用含有泛型的方法的时候,需要给该泛型进行确认
-
明确时机:
调用方法进行传递参数时
public class MyList<AT> {
public void add (AT at) {
System.out.println("添加元素");
}
public <AGG> AGG method (AGG agg) {
System.out.println(agg.getClass().getName());
return null;
}
}
public class CollectionDemo10 {
public static void main(String[] args) {
MyList<String> myList = new MyList<>();
myList.add("123");
myList.method(new Integer(1));
}
}
2.4 泛型的高级应用
2.4.1 泛型的通配符
-
含义:对含有泛型的方法的简化
-
前提条件:方法的形参是含有泛型的类或者接口类型
-
声明格式:
-
泛型普通格式使用:
修饰符 <泛型> 返回值类型 方法名 (含有泛型的类名或者接口名<泛型> 对象名) {}
-
上述格式简化如下:
修饰符 返回值类型 方法名 (含有泛型的类名或者接口名<?> 对象名) {}
-
2.4.2 上限
-
格式
<? extends 泛型> 泛型的类型只允许泛型类型本身或者是该类型的子类类型
2.4.3 下限
-
格式
<? super 泛型> 泛型的类型只允许泛型类型本身或者是该类型的父类类型
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo14 {
public static void main(String[] args) {
//A是B的父类,B是C的父类
Collection<String> str = new ArrayList<>();
Collection<Object> obj = new ArrayList<>();
Collection<A> a = new ArrayList<>();
Collection<B> b = new ArrayList<>();
Collection<C> c = new ArrayList<>();
MyList myList = new MyList();
myList.method(str);
myList.method(obj);
myList.method(a);
myList.method(b);
myList.method(c);
// myList.show(str);
// myList.show(obj);
// myList.show(a);
myList.show(b);
myList.show(c);
// myList.show1(str);
myList.show1(obj);
myList.show1(a);
myList.show1(b);
// myList.show1(c);
}
}
import java.util.Collection;
public class MyList {
public void method (Collection<?> coll) {
System.out.println(coll.getClass());
}
public void show (Collection<? extends B> coll) {}
public void show1 (Collection<? super B> coll) {}
}
3、List接口
- 特点:
- 有序的集合
- 有索引的集合
- 可以有重复元素
- List接口的实现类们一共有四种形成索引的方式:数组结构、链表结构、(栈、队列)
- 位置:java.util
- 方法
-
void add(int index,E element)
在列表的指定位置插入指定元素(可选操作)。
-
E get(int index)
返回列表中指定位置的元素。
-
int indexOf(Object o)
返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
-
int lastIndexOf(Object o)
返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
-
ListIterator listIterator()
返回此列表元素的列表迭代器(按适当顺序)。
-
E remove(int index)
移除列表中指定位置的元素(可选操作)。
-
E set(int index,E element)
用指定元素替换列表中指定位置的元素(可选操作)。
-
List subList(int fromIndex,int toIndex)
返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
3.1 List集合的五种遍历方式
- 迭代器
- 增强for(JDK5.0)
- Stream流(JDK8.0)
- List特有迭代器:listIterator
- 普通for
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.stream.Stream;
public class ListDemo01 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
ListIterator<String> stringListIterator = list.listIterator();
while (stringListIterator.hasNext()){
System.out.println(stringListIterator.next());
}
for (String s : list) {
System.out.println(s);
}
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
3.2 List集合删除时的注意事项(remove方法)
-
集合删除时的注意事项:
集合的长度和索引在进行删除后都是变化的
- 解决方案
- 每次删除成功,将索引进行-1
- 倒序删除
- 迭代器
补充:使用String类的equals()时,习惯使用字符串字面值常量进行调用,将变量传入方法中,这样可以避免空指针异常
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo04 {
public static void main(String[] args) {
method2();
}
private static void method() {
List<String> list = new ArrayList<>();
list.add("100元");
list.add("100元");
list.add("100元");
list.add("50元");
list.add("10元");
for (int i = 0; i < list.size(); i++) {
if ("100元".equals(list.get(i))){
list.remove(i);
i--;
}
}
System.out.println(list);
}
private static void method1() {
List<String> list = new ArrayList<>();
list.add("100元");
list.add("100元");
list.add("100元");
list.add("50元");
list.add("10元");
for (int i = list.size() - 1; i >= 0; i--) {
if ("100元".equals(list.get(i))){
list.remove(i);
}
}
System.out.println(list);
}
private static void method2() {
List<String> list = new ArrayList<>();
list.add("100元");
list.add("100元");
list.add("100元");
list.add("50元");
list.add("10元");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String str = iterator.next();
if ("100元".equals(str)){
iterator.remove();
}
}
System.out.println(list);
}
}
4、ArrayList集合类
-
特点:
-
ArrayList集合底层数据结构:数组结构
-
数组结构的特点:查询效率高,增删效率低
-
ArrayList集合可以存储null元素,获取时需要针对所有元素进行非空校验,否则可能空指针异常
-
线程不安全,适用于单线程程序,执行效率高。如果在多线程中进行使用需要手动添加线程安全
-
ArrayList集合底层数组的初始容量:取决于构造器
(1)ArrayList()无参构造器:
JDK6.0(包含)以前:10
JDK7.0(包含)以后:0,在第一次添加元素时初始化为10
(2)ArrayList(Collection<? extends E> c)
参数长度
(3)ArrayList(int initialCapacity)
自定义容量
-
扩容
JDK6.0(包含)以前:(原来数组长度*3)/2-1
JDK7.0(包含)以后:原来数组长度+原来数组长度 >> 1
-
5、Vector类
- 特点:被ArrayList替代(JDK1.2),与ArrayList同。
-
Vector集合底层数据结构:数组结构
-
数组结构的特点:查询效率高,增删效率低
-
Vector集合可以存储null元素,获取时需要针对所有元素进行非空校验,否则可能空指针异常
-
线程安全,适用于多线程程序,执行效率低。
-
Vector集合底层数组的初始容量和增量:取决于构造器
(1)Vector()无参构造器:
初始容量:10
增量:0
(2)Vector(Collection<? extends E> c)
初始容量:参数长度
增量:0
(3)ArrayList(int initialCapacity)
初始容量:自定义容量
增量:0
(4)ArrayList(int initialCapacity,int capacityincremental)
初始容量:自定义容量
增量:自定义容量
-
扩容
原来数组长度+((增量 > 0) ?增量 :原来数组长度 )
- 位置:java.util
6、LinkedList类
-
特点
List接口的(双向)链接列表实现。相比于数组,查询效率低,增删效率高
线程不安全
可以存储null
-
方法:
-
public void addFirst(E e)
将指定元素插入此列表的开头。
-
public void addLast(E e)
将指定元素添加到此列表的结尾。
-
public E getFirst()
返回此列表的第一个元素。
-
public E getLast()
返回此列表的最后一个元素。
-
public E removeFirst()
移除并返回此列表的第一个元素。
-
public E removeLast()
移除并返回此列表的最后一个元素。
7、List小结
- 如果操作的数据查询偏多,选择ArrayList集合;
- 如果操作的数据增删偏多,选择LinkedList集合;
- 如果涉及线程安全,选择Vector或者根据实际情况选择ArrayList和LinkedList并手动给其添加线程安全
Today Code
collection:
- 集合的概述
- Collection接口
- Collection集合的面试题
- Collection通用的遍历方式:迭代器
- 迭代器的注意事项
- 增强for
- 增强for的注意事项
- Stream流
- 泛型的概述
- 含有泛型的类
- 含有泛型的接口
- 含有泛型的方法
- 泛型的高级应用
- 泛型的受限
list:
- List接口
- List接口的方法
- List集合的五种遍历方式
- List集合删除时的注意事项(remove方法)
- ArrayList实现类
- Vector类
- LinkedList类
- List小结