Collection集合
- 集合其实就是一种容器,可以用来存储多个引用类型的数据(分为单列集合,双列集合)
单列集合: 以单个单个元素进行存储
双列集合: 以键值对的方式进行存储
- 集合与数组的区别
数组长度是固定的
集合长度是不固定的
数组可以存储基本类型+引用类型
集合只能存储引用类型,如果要存储基本类型,需要存储基本类型对应的包装类类型
单列集合常用类的继承体系_
- 单列集合: 以单个单个元素进行存储
- 单列集合继承体系:
Collection接口是所有单列集合的根接口,也就意味着所有的单列集合都实现了Collection接口
-
List接口继承Collection接口:List集合元素
有索引
,元素存取有序
,元素可重复
- ArrayList类: 数组存储结构,查询快,增删慢
- LinkedList类: 链表存储结构,查询慢,增删快
-
Set接口继承Collection接口: Set集合元素
没有索引
,元素不可重复
(唯一)
- HashSet类:哈希表结构,由哈希表保证元素唯一
,元素存取无序
,不可以排序
- LinkedHashSet类:链表+哈希表结构,由哈希表保证元素唯一
,由链表保证元素存取有序
,不可以排序
- TreeSet类:二叉树结构,可以对元素进行排序
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()
: 把集合中的元素,存储到数组中
Collection<String> list = new ArrayList<>();
// 把给定的对象添加到当前集合中
list.add("张三");
list.add("李四");
list.add("王五");
// 输出 list = [张三, 李四, 王五]
System.out.println("list = " + list);
// 把给定的对象在当前集合中删除
list.remove("李四");
// 输出 list = [张三, 王五]
System.out.println("list = " + list);
// 判断当前集合中是否包含给定的对象
System.out.println(list.contains("张三")); // 输出 true
// 判断当前集合是否为空
System.out.println(list.isEmpty());// 输出 False
// 返回集合中元素的个数
System.out.println(list.size());// 输出 2
// 把集合中的元素,存储到数组中 (Arrays.toString 把数组以字符串的形式输出)
System.out.println(Arrays.toString(list.toArray()));// 输出 [张三, 王五]
// 清空集合中所有的元素
list.clear();
System.out.println("list = " + list );// 输出 list = []
Iterator迭代器_
- 迭代即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。一直把集合中的所有元素全部取出
- 迭代的步骤:
- 获取迭代器对象
- 使用迭代器对象判断集合中是否有元素可以取出
- 如果有元素可以取出,就直接取出来该元素,如果没有元素可以取出,就结束迭代
获取迭代器对象_
- Iterator迭代器对象的常用方法
-public boolean hasNext()
:如果仍有元素可以迭代,则返回 true。
-public E next()
:返回迭代的下一个元素。
-void remove()
删除当前迭代出来的元素
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Text2 {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
// 向集合中添加元素
list.add("张三");
list.add("李四");
list.add("王五");
list.add("老六");
// 通过集合对象获取对应的迭代器对象
Iterator<String> it = list.iterator();
// 循环判断是否有元素可以迭代
while(it.hasNext()){
// 如果有就在循环中取出可以迭代的元素
String e = it.next();
System.out.println(e);// 输出 张三
// 李四
// 王五
// 老六
// 如果迭代出来的元素是老六,就删除该元素
if("老六".equals(e)){
it.remove();
}
}
System.out.println(list);// 输出 [张三, 李四, 王五]
}
}
注意:在进行集合元素获取时,如果集合中已经没有元素可以迭代了,还继续使用迭代器的next方法,将会抛出
NoSuchElementException
没有集合元素异常
注意:在进行集合元素迭代时,如果添加或移除集合中的元素 , 将无法继续迭代 , 将会抛出
ConcurrentModificationException
并发修改异常(使用迭代器的remove方法可以一边迭代一边删除)
- 解决办法:
- 使用CopyOnWriteArrayList
集合,就可以迭代的时候,往集合中添加或删除元素
增强for
- 是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和Collection集合
内部基于Iterator迭代器实现,所以在遍历的过程中,不能对集合中的元素进行增删操作,否则抛出ConcurrentModificationException并发修改异常
import java.util.ArrayList;
import java.util.Collection;
public class Text2 {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("老六");
for (String e : list) {
System.out.println(e);
//输出
// 张三
// 李四
// 王五
// 老六
}
}
}
泛型
- JDK5之后,新增了泛型(Generic)语法,可以在类、接口或方法中预支地使用未知的类型
好处:
- 将运行时期的ClassCastException,转移到了编译时期变成了编译失败
- 避免了类型转换的麻烦
定义含并使用含有泛型的类_
// 定义一个含有泛型的类
class Show<E>{
// 定义一个形参为泛型的方法
public void a(E e){
System.out.println(e);
}
}
public class Text3 {
public static void main(String[] args) {
// 创建对象时给定确定的数据类型,那么泛型类中所有被定义为泛型的位置就都是给定的数据类型
new Show<String>().a("HelloWorld"); // 输出 HelloWorld
new Show<Integer>().a(10);// 输出 10
}
}
定义并使用含有泛型的方法_
// 定义一个含有泛型的类
class Show<E>{
// 定义一个形参和返回值类型都为泛型的方法
public E a(E e){
return e;
}
}
public class Text3 {
public static void main(String[] args) {
// 创建对象时给定确定的数据类型,那么泛型类中所有被定义为泛型的位置就都是给定的数据类型
System.out.println(new Show<String>().a("HelloWorld")); // 输出 HelloWorld
System.out.println(new Show<Integer>().a(10));// 输出 10
}
}
定义并使用含有泛型的接口_
// 定义一个含有泛型的类
interface Show<E>{
// 定义一个形参和返回值类型都为泛型的方法
public abstract E a(E e);
}
// 被实现的类也不确定具体的数据类型,而是创建实现类对象的时候确定泛型的具体数据类型
class a<E> implements Show<E>{
@Override
public E a(E e) {
return e;
}
}
public class Text3 {
public static void main(String[] args) {
// 创建对象时给定确定的数据类型,那么泛型类中所有被定义为泛型的位置就都是给定的数据类型
System.out.println(new a<String>().a("Abc")); // 输出 Abc
}
}
泛型通配符_
- 泛型通配符用问号表示(?)
泛型通配符的用处:
泛型本身不存在继承关系,不可以给已指定泛型的变量接收有其他泛型类型的对象
如果想要使变量在未来接收有泛型定义的对象,又不确定泛型要定义的类型可以使用泛型通配符
Collection<?> list 变量接收
注意:
- 如果使用了泛型通配符,那么该集合变量元素类型默认是Object类型
- 如果使用了泛型通配符,那么该集合变量只能取元素,无法增删元素
class Demo<E>{}
public class Text4 {
public static void main(String[] args) {
// 并不会报错
func(new Demo<String>());
func(new Demo<Integer>());
func(new Demo<Object>());
func(new Demo<Number>());
}
public static void func(Demo<?> a){
// 注意: 如果使用了泛型通配符,那么该集合元素类型默认是Object类型
System.out.println("执行了..."); // 输出 执行了
}
}
通配符高级使用 - 受限泛型_
<? extends 类名>
表示: 只接受该类类型或者其子类类型<? super 类名>
表示: 只接受该类类型或者其父类类型
public class Test {
public static void main(String[] args) {
// Integer继承Number,Number继承Object,String继承Object
ArrayList<Object> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
ArrayList<Integer> list3 = new ArrayList<>();
ArrayList<Number> list4 = new ArrayList<>();
method1(list1);
//method1(list2);// 编译报错
method1(list3);
method1(list4);
//method2(list1);// 编译报错
//method2(list2);// 编译报错
method2(list3);
method2(list4);
}
// 定义一个方法,只可以接收泛型是Integer或者其父类类型的ArrayList集合对象
public static void method1(ArrayList<? super Integer> list){
list.add(100);
}
// 定义一个方法,只可以接收泛型是Number或者其子类类型的ArrayList集合对象
public static void method2(ArrayList<? extends Number> 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)
:用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
import java.util.ArrayList;
import java.util.List;
public class Text5 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 在集合的后面添加元素
list.add("张三");
list.add("李四");
list.add("王五");
list.add("老六");
System.out.println("list = " + list); // list = [张三, 李四, 王五, 老六]
// 将指定的元素,添加到该集合中的指定位置上
list.add(0,"java");
System.out.println("list = " + list); // list = [java, 张三, 李四, 王五, 老六]
// 返回集合中指定位置的元素
System.out.println(list.get(0)); // java
// 移除列表中指定位置的元素, 返回的是Boolean值
System.out.println(list.remove("Hello"));
// 用指定元素替换集合中指定位置的元素,返回更新前的值
System.out.println(list.set(0, "C++")); // java
System.out.println("list = " + list);// list = [C++, 张三, 李四, 王五]
}
}
注意:
如果集合元素为Integer类型,那么删除的时候优先根据索引删除
List的子类_
- ArrayList集合: 底层采用的是数组结构,查询快,增删慢
- 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)
:将元素推入此列表所表示的堆栈
import java.util.LinkedList;
public class Text6 {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("老六");
System.out.println("list = " + list); // list = [张三, 李四, 王五, 老六]
// 将指定元素插入此列表的开头
list.addFirst("Abc");
System.out.println("list = " + list); // list = [Abc, 张三, 李四, 王五, 老六]
// 将指定元素添加到此列表的结尾
list.addLast("deF");
System.out.println("list = " + list);// list = [Abc, 张三, 李四, 王五, 老六, deF]
// 返回此列表的第一个元素
System.out.println(list.getFirst());// Abc
// 返回此列表的最后一个元素
System.out.println(list.getLast());// deF
// 移除并返回此列表的第一个元素
System.out.println(list.removeFirst());// Abc
System.out.println("list = " + list); // list = [张三, 李四, 王五, 老六, deF]
// 移除并返回此列表的最后一个元素
System.out.println(list.removeLast());// deF
System.out.println("list = " + list);// list = [张三, 李四, 王五, 老六]
// 将元素推入此列表所表示的堆栈
list.push("java");
System.out.println("list = " + list);// list = [java, 张三, 李四, 王五, 老六]
// 从此列表所表示的堆栈处弹出一个元素
list.pop();
System.out.println("list = " + list);// list = [张三, 李四, 王五, 老六]
}
}