前言
在学习泛型前,我们得明白为什么要学习这个!!!,在JAVA SE 5.0前,ArrayList类只维护一个Object数组,使得在后面获取元素时,需要我们自己将Object对象强制类型转换 。这时候就很容易引起ClassCastException异常。因此在JAVA SE 5.0 引进了泛型,可以在编译时检查非法数据类型。
1、泛型的概念
泛型允许你在定义类、接口和方法时使用类型参数。这些类型参数在实际使用时会被具体的类型所替换,从而使得同一个代码可以被很多不同类型的对象所重用。
2、泛型体系
2.1 泛型类
2.1.1 泛型类语法
常用泛型标识:T、E、K、V
class 类名称 <泛型标识,泛型标识...>{
private 泛型标识 变量名;
}
public class Common <T>{
private T value;
public Common(T value) {
this.value = value;
}
public Common() {
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
@Override
public String toString() {
return "Common{" +
"value=" + value +
'}';
}
}
public class Client {
public static void main(String[] args) {
//泛型类在创建对象的时候指定操作的具体数据类型(泛型类不支持基本数据类型)
Common<Integer> commonInteger = new Common<>(2);
//输出 Common{value=2}
System.out.println(commonInteger);
Common<String> commonString = new Common<>("A");
//输出 Common{value=A}
System.out.println(commonString);
}
}
注意点:
(1)泛型类在创建对象的时候指定需要操作的数据类型。
(2)未指名具体的操作类型,则默认为Object类型。泛型不支持基本数据类型。
(3)泛型本质上都是类类型
(4)子类(泛型类)继承父类(泛型类),子类与父类泛型需要一致。
(5)子类(非泛型类)继承父类(泛型类),父类需要指明具体类型。
2.2 泛型接口
2.2.1 泛型接口语法
interface 接口名<泛型标识,泛型标识...> {
泛型标识 方法名();
}
2.2.1 用法
(1)定义一个泛型接口
public interface Generics<T> {
T getValue();
}
(2) 定义一个类去实现泛型接口
实现类不是泛型类。需要去明确泛型接口数据类型。如果不指明泛型接口的具体类型是什么,那么方法默认为Object类型。
实现类是泛型类。实现类与接口类型一致
public class GenericsImpl implements Generics{
@Override
public Object getValue() {
return null;
}
}
2.3 泛型方法
2.3.1 泛型方法语法
只有申明了<T>的方法才是泛型方法,在泛型类中使用泛型成员方法不是泛型方法。
修饰符 <T,E...> 返回值 方法名称(形参列表){
方法体...
}
public class GenericMethodExample {
// 定义一个泛型方法
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
public static void main(String[] args) {
// 使用泛型方法
Integer[] intArray = {1, 2, 3, 4, 5};
String[] stringArray = {"Hello", "World"};
printArray(intArray);
printArray(stringArray);
}
}
2.4 类型通配符
2.4.1 类型通配符的定义
类型通配符一般是使用“?”代替具体类型实参。使用上面已经定义好的泛型类Common来举例。
public class Client {
public static void main(String[] args) {
Common<Number> value1 = new Common<>();
value1.setValue(100);
getValue(value1);
Common<Integer> value2 = new Common<>();
value1.setValue(200);
getValue(value2);
}
public static void getValue(Common<Number> common){
Number value = common.getValue();
System.out.println(value);
}
}
目前这段代码报了一个错(需要Number类型,但是我们传递了一个Integer类型),明明Integer是Number子类却报错了,我们不能已多态的思想去看待泛型。那我们要怎么解决这个问题?重新复制粘贴一个方法,nonono,这里就可以使用上类型通配符,代表着一个不确定的类型。
2.4.2 类型通配符的上限
类/接口<? extends 实参类型>
要求泛型类型,是实参类型/实参类型的子类。
2.4.3 类型通配符的上限
类/接口<? super 实参类型>
要求泛型类型,是实参类型/实参类型的父类。