写在前面:
视频是什么东西,有看文档精彩吗?
视频是什么东西,有看文档速度快吗?
视频是什么东西,有看文档效率高吗?
泛型类
诸小亮:接着我们聊一聊——泛型类
张小飞:泛型类是什么意思?
诸小亮:泛型类——在定义类时,使用:类名<泛型> 这种形式的都是泛型类,比如:
//<T>:表示定义一个泛型T,T:是随便起的名字,可以小写,但一般都是大写
class Tool<T>{//如果要定义多个泛型,使用逗号分隔,比如:<T,E>
}
张小飞:Tool 就是一个泛型类?就这么简单?
诸小亮:没错,就这么简单,集合框架中的 ArrayList、LinkedList、HashSet等都是泛型类
为什么需要泛型类?
张小飞:原来如此,我听说泛型可以——提高代码的重用性和安全性?
诸小亮:是的,
张小飞:能否具体说一说?
诸小亮:来,我们自定义一个集合类,用于处理 Hero 类型的数据
public class HeroList {
//用于测试,只存储 10 个对象
private Hero[] items = new Hero[10];
private int size = 0;
public void add(Hero item) {
items[size++] = item;
}
public Hero get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
return items[index];
}
}
张小飞:然后呢?
诸小亮:如果现在又想自定义一个集合类,处理 Person 类型的数据,怎么办?
张小飞:这还不简单,看我的
public class PersonList {
//用于测试,只存储 10 个对象
private Person[] items = new Person[10];
private int size = 0;
public void add(Person item) {
items[size++] = item;
}
public Person get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
return items[index];
}
}
诸小亮:你有没有发现一个问题,HeroList 和 PersonList 代码都差不错,非常相似
张小飞:嗯,发现了,那,这样行不行?
public class ObjectList {
//用于测试,只存储 10 个对象
private Object[] items = new Object[10];
private int size = 0;
public void add(Object item) {
items[size++] = item;
}
public Object get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
return items[index];
}
}
诸小亮:这样做确实节省了一些代码量,不过操作都是 Object 啊
张小飞:有什么问题吗?
诸小亮:因为 Object 是所有类的父类,所以可以添加任何类型的数据
但在使用时可能需要进行类型转换,而类型转换可能会引起运行时错误,比如:
ObjectList list = new ObjectList();
list.add("Hello");
String s = (String) list.get(0);
张小飞:这也没什么问题啊
诸小亮:不要着急,还没有写完呢,看下面
list.add(123);
String s = (String) list.get(1);
张小飞:你添加了一个 int 类型,取出来的时候转换为 String ,肯定报错啊
诸小亮:是啊,那应该怎么办呢?
张小飞:可以先用 instanceof 判断它是什么类型的
诸小亮:判断?每个类都是一种数据类型,你怎么判断?
张小飞:这。。。。
诸小亮:这个时候就可以使用泛型,看下面代码
public class ObjectList<T> {
//用于测试,只存储 10 个对象
private T[] items = new T[10];
private int size = 0;
public void add(T item) {
items[size++] = item;
}
public T get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
return items[index];
}
}
诸小亮:使用泛型类型 T 数组存储元素,将 add() 方法的参数类型设置为 T,get() 方法的返回值类型也是 T
GenericList<String> list = new GenericList<>();
list.add("Hello");
String s = list.get(0); // 不需要进行类型转换
诸小亮:使用泛型类的好处
- 提高代码复用率
- 在编译时就可以检查类型安全性,避免在运行时出现类型转换错误;
- 可以避免使用时进行类型转换,代码更加简洁、易读;
张小飞:明白了,不过具体说明时候使用泛型类呢?
诸小亮:当需要操作的数据类型不明确时,就应该使用泛型,具体操作那种类型,然用户在使用时自己指定
成员方法中使用泛型
诸小亮:在泛型类中的方法中使用泛型,还需要注意两点
张小飞:哪两点?
诸小亮:在类上定义过泛型后,在方法上可以直接使用
//<T>:表示定义一个泛型T,T:是随便起的名字,可以小写,但一般都是大写
class Tool<T>{
//因为,类上已经定义,索引方法中就可以使用 T 这种类型,
//当前方法,参数是T类型,返回值也是T类型
//也就是说,参数和返回值必须是同一种类
public T assemble(T t){
//TODO 各种配置
return t;
}
}
使用:
public static void main(String[] args) throws Exception {
Tool<Hero> tool = new Tool<Hero>();//可以简写:Tool<Hero> tool = new Tool<>();
//1. assemble 既可以处理 Hero 类型的数据
Hero yase = tool.assemble(new Hero("yase"));
//2. 也可以处理 Person 类型的数据
Tool<Person> tool = new Tool<Person>();
Person lvbu = tool.assemble(new Person("lvbu"));
}
张小飞:了解
诸小亮:另外,如果创建Tool对象时候,没有指定类型,则:
诸小亮:因为 tool 对象创建时没有指定类型,所以 assemble 的返回值,只能使用 Object 接收
张小飞:使用 Hero 接收,竟然直接报错:
诸小亮:是的,所以做好是提前指定泛型
张小飞:明白了
成员变量使用泛型
张小飞:泛型类种的普通成员变量也可以直接使用泛型吗?
诸小亮:当然可以,比如:
//<T>:表示定义一个泛型T,T:是随便起的名字,可以小写,但一般都是大写
class Tool<T>{
T name;//表示name属于T类型
}
使用:
public static void main(String[] args) {
Tool<String> tool = new Tool<String>();
//name 属性,这时候只能存储String
tool.name = "yase";
Tool<Integer> tool2 = new Tool<Integer>();
//name 属性,这时候只能存储Integer
tool2.name = 110;
}
张小飞:如果创建 Tool 对象时候,没有指定类型呢?
诸小亮:那就什么类型都可以设置了,比如:
上图,name既可以是字符串,又可以是数字,但是一般不推荐这样使用
原因:
- 使用泛型的目的就是为了限定数据类型
- 如果使用上图的方式,还不如定义name属性时候:Objec name;
泛型类注意点
诸小亮:如果类名那里没有定义泛型,那么在类的成员中不能随意使用,比如:
上图,因为类名那里没有定义T,所以 属性、方法 中不能随意使用
诸小亮:另外,静态方法中不能使用类名上定义的泛型
张小飞:嗯嗯,我记下了