一 、Collection接口
1 、基本关系说明
Java 集合框架Java Collection Framework ,又被称为容器container ,是定义在 java.util 包下的一组接口interfaces 和其实现类classes 。
其主要表现为将多个元素element 置于一个单元中,用于对这些元素进行快速、便捷的存储store 、检索retrieve 、管理manipulate ,即平时我们俗称的增删查改CRUD 。
Collection :用来存储管理一组对象objects ,这些对象一般被成为元素elements
- Set : 元素不能重复,背后隐含着查找/搜索的语义
- SortedSet : 一组有序的不能重复的元素
- List : 线性结构
- Queue : 队列
- Deque : 双端队列
2、 Collection 常用方法说明
3、 代码示例
下面示例代码涉及到ArrayList将在后面博客详细介绍,此处仅仅是作为例子使用。
import java.util.Collection;
import java.util.ArrayList;
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
System.out.println(list.size());//获取元素个数
System.out.println(list.isEmpty());//判断是否为空
//添加元素
list.add("我");
list.add("爱");
list.add("Java");
System.out.println(list.size());
System.out.println(list.isEmpty());
//将list转为对象数组
Object[] array = list.toArray();
//打印数组内容
System.out.println(Arrays.toString(array));
for (String s : list) {
System.out.println(s);
}
//删除元素
list.remove("爱");
for (String s : list) {
System.out.println(s);
}
//清空
list.clear();
System.out.println(list.size());
System.out.println(list.isEmpty());
}
二 、泛型(Generic)
1 、泛型的诞生
我们之前实现过的顺序表,只能保存 int 类型的元素,如果现在需要保存 指向 Person 类型对象的引用的顺序表,请问应该如何解决?如果又需要保存指向 Book 对象类型的引用呢?
答:将我们的顺序表的元素类型定义成 Object 类型,这样我们的 Object 类型的引用可以指向 Person 类型的对象或者指向 Book 类型的对象了。
代码示例:
public class MyArrayList {
private Object[] array; // 保存顺序表的元素,即 Object 类型的引用
private int size; // 保存顺序表内数据个数
public void add(Object o) { 尾插 }
public Object get(int index) { 获取 index 位置的元素 }
}
//使用
MyArrayList books = new MyArrayList();
for (int i = 0; i < 10; i++) {
books.add(new Book()); // 尾插 10 本书到顺序表
}
如上述代码所示,链表中就可以添加任意类型的成员了。
但是如果直接父类引用改为具体的类型还可以吗?看下面代码:
MyArrayList books = new MyArrayList();
books.add(new Book);
// 将 Object 类型转换为 Person 类型,需要类型转换才能成功
// 这里编译正确,但运行时会抛出异常 ClassCastException
Person person = (Person)books.get(0);
此时将Object 类型转换为 Person 类型在编译时期正确,但是在运行时会抛出ClassCastException异常。
所以我们需要这样一种机制:
- 增加编译期间的类型检查
- 取消类型转换的使用
因此, 泛型就此诞生!
2 、泛型的分类以及使用
1) 、泛型分类
泛型主要有两大分类:
- 1.泛型类
- 2.泛型方法
2) 、泛型类的使用
- 1.尖括号 <> 是泛型的标志
- 2.E 是类型变量(Type Variable),变量名一般要大写
- 3.E 在定义时是形参,代表的意思是 MyArrayList 最终传入的类型,但现在还不知道
代码:
public class MyArrayList<E> {
private E[] array;
private int size;
}
注意: 泛型类可以一次有多个类型变量,用逗号分割。
// 定义了一个元素是 Book 引用的 MyArrayList
MyArrayList<Book> books = new MyArrayList<Book>();
books.add(new Book());
// 会产生编译错误,Person 类型无法转换为 Book 类型
books.add(new Person());
// 不需要做类型转换
Book book = book.get(0);
// 不需要做类型转换
// 会产生编译错误,Book 类型无法转换为 Person 类型
Person person = book.get(0);
通过以上代码,我们可以看到泛型类的一个使用方式:只需要在所有类型后边跟尖括号,并且尖括号内是真正的类型,即 E 可以看作的最后的类型。
注意: Book 只能想象成 E 的类型,但实际上 E 的类型还是 Object。
3) 、泛型方法的使用
泛型方法的使用:方法中的参数可以接收任意类型的参数
public class Tool {
public <E> hello(E t){
System.out.println(t);
}
}
public class Main {
public static void main(String[] args) {
Tool tol= new Tool ();
tol.hello("wy");
}
}
3 、泛型总结
1. 泛型是为了解决某些容器、算法等代码的通用性而引入,并且能在编译期间做类型检查。
2. 泛型利用的是 Object 是所有类的祖先类,并且父类的引用可以指向子类对象的特定而工作。
3. 泛型是一种编译期间的机制,即运行期间没有泛型的概念。也就是说MyArrayList< Person>和 MyArrayList< Book> 在运行期间是一个类型。
4. 泛型是 java 中的一种合法语法,标志就是尖括号 <>
三 、包装类(Wrapper Class)
1 、为什么会有包装类型呢?
问题一: 泛型利用Object 引用可以指向任意类型的对象,但有8 种基本数据类型不是对象,那岂不是刚才的泛型机制要失效了?
答: 实际上也确实如此,为了解决这个问题,java 引入了一类特殊的类,即这 8 种基本数据类型的包装类,在使用过程中,会将类似 int 这样的值包装到一个对象中去。
问题二: 如果我们在项目中自定义类的数据成员为简单类型,当没有初始化,它默认是对应的零值(比如int就是0),这样就会对数据造成误解,到底是该数据为0还是默认是0呢?
答: 基本数据类型的确会对数值咋成误解,但是Integer这样的包装类型没有初始话就是null,并不会对数值造成误解。
2 、基本数据类型和包装类直接的对应关系
基本就是类型的首字母大写,除了 Integer 和 Character。
3 、包装类的使用
1)装箱(boxing)和拆箱(unboxing)
- 装箱操作:将基本数据类型转为包装数据类型
- 拆箱操作:将包装数据类型转为基本数据类型
代码示例:
int i = 10;
// 装箱操作,新建一个 Integer 类型对象,将 i 的值放入对象的某个属性中
Integer ii = Integer.valueOf(i);
Integer ij = new Integer(i);
// 拆箱操作,将 Integer 对象中的值取出,放到一个基本数据类型中
int j = ii.intValue();
1)自动装箱(autoboxing)和自动拆箱(autounboxing)
可以看到在使用过程中,装箱和拆箱带来不少的代码量,所以为了减少开发者的负担,java 提供了自动机制。
int i = 10;
Integer ii = i; // 自动装箱
Integer ij = (Integer)i; // 自动装箱
int j = ii; // 自动拆箱
int k = (int)ii; // 自动拆箱
注意: 自动装箱和自动拆箱是工作在编译期间的一种机制。