Java基础复习 —— 泛型
泛型
简介
-
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
-
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数
-
泛型的作用是可以在类声明时,通过标识表示类中某个属性的类型,或者某个方法的返回值类型,或者是参数类型
泛型的好处
-
减少了类型转换的次数,提高效率
-
编译时,检查添加元素的类型,提高安全性
Java 泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生 ClassCastException异常,同时代码更简洁、健壮
-
编写的代码可以被不同类型的对象所复用
泛型的声明
interface 接口名 <T> {} // 泛型接口
class 类名 <K,V> {} // 泛型类
- 其中,T,K 和 V 是类型标识,不代表值
- 任意字母都可以,通常使用
- T - Type(Java 类)
- E - Element (在集合中使用,因为集合中存放的是元素)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
泛型的实例化
ArrayList<String> strList = new ArrayList<String>();
Iterator<Custom> iterator = customs.iterator();
泛型使用的注意事项和细节
-
注意类型参数只能代表引用类型,不能是基本数据类型(像 int、double、char 等)。
-
给泛型指定具体类型后,可以传入该类型的或其子类类型
public class Generic02 { public static void main(String[] args) { Cat<A> cat1 = new Cat<>(new A()); // 传入A类 Cat<A> cat2 = new Cat<>(new B()); // 构造方法传入A的子类B } } class A { } class B extends A { } class Cat<E> { E e; public Cat(E e) { this.e = e; } }
-
如果不指明具体类型,默认为 Object
ArrayList arrayList = new ArrayList();//等价 ArrayList<Object> arrayList = new ArrayList<Object>()
-
可以简写
ArrayList<Integer> list1 = new ArrayList<Integer>(); List<Integer> list2 = new ArrayList<>(); // 推荐使用简写
自定义泛型
自定义泛型类
class 类名 <T, R...> { // 可以是一个或多个泛型参数
. . .
}
- 普通成员可以使用泛型(属性,方法)
- 使用泛型的数组不能初始化
- 静态方法中不能使用类的泛型
- 泛型类的类型,是在创建对象时确定的(创建对象时,需要指定确定的类型)
- 如果创建对象时,没有指定类型,默认为Object
class Cat<T, R, M> {
String name;
T t;
R r;
M m;
// T[] ts = new T[3];
// Type parameter 'T' cannot be instantiated directly
// 因为数组在 new 时不能确定 T 的类型, 就无法在内存开空间
T[] ts; // 可以声明
//static R r2;
// 因为静态是和类相关的, 在类加载时, 对象还没有创建
// /所以, 如果静态方法和静态属性使用了泛型, JVM 就无法完成初始化
}
自定义泛型接口
interface 接口名 <T, R, ...> {
}
- 接口中,静态成员也不能使用泛型
- 泛型接口的类型,在继承或者实现接口时确定
- 没有指定类型,默认Object
interface IUsb<U, R> {
// U u ;
// 接口中成员默认 static,不能这样使用
// 抽象方法中, 可以使用接口泛型
R get(U u);
void hi(R r);
void run(R r1, R r2, U u1, U u2);
//在 jdk8 中, 可以在接口中, 默认方法, 也是可以使用泛型
default R method(U u) {
return null;
}
}
interface AA extends IUsb<Integer, String> {
}
//子接口泛型可以比父接口多,子类泛型可以比父类多
interface BB<U, R,V> extends IUsb<Double, String> {
}
//在继承接口 指定泛型接口的类型
interface CC<U, R> extends IUsb<U, R> {
}
//没有指定类型, 默认为 Object
// 等价于 interface DD extends IUsb<Object,Object>
interface DD extends IUsb {
}
// 实现接口时, 直接指定泛型接口的类型
class EE implements IUsb<Double, Float> {
@Override
public Float get(Double aDouble) {
return null;
}
@Override
public void hi(Float aFloat) {
}
@Override
public void run(Float r1, Float r2, Double u1, Double u2) {
}
}
自定义泛型方法
修饰符 <T, R> 返回类型 方法名(参数列表){
}
-
泛型方法,可以定义在普通类中,亦可以定义在泛型类中
-
当泛型方法被调用时,类型会确定
-
public void eat(E e){}
修饰符之后没有泛型标识符 <T,...> ,eat方法不是泛型方法,而是使用了泛型public class CustomGenericMethod01 { public static void main(String[] args) { new Car().fly("bmw", 10012); // //当调用方法时, 传入参数, 编译器, 就会确定类型 Fish<String, ArrayList> fish = new Fish<>(); fish.hello("hi", 11.2F); } } // 普通类 class Car { public void run() { } public <T, E> void fly(T t, E e){ System.out.println(t.getClass()); System.out.println(e.getClass()); } } //泛型类 class Fish<T, E> { public void run() { } // 泛型方法 public <U, M> void fly(U u, M m){ System.out.println(u.getClass()); System.out.println(m.getClass()); } // 泛型方法, 可以使用类声明的泛型, 也可以使用自己声明泛型 public<K> void hello(T t, K k) { System.out.println(t.getClass());//ArrayList System.out.println(k.getClass());//Float } }
泛型的继承和通配符
-
泛型不具备继承性
List<Object> strings = new ArrayList<String>(); // 错误 不兼容的类型
-
<?>
支持任意泛型类型 -
<? extends A>
: 支持A类及A的子类,规定了泛型的上限 -
<? super A>
:支持A类及A的父类,不限于直接法雷,规定了泛型的下限
public class GenericHeritance {
public static void main(String[] args) {
Object o = new String("xx");
//泛型没有继承性
//List<Object> list = new ArrayList<String>();
//举例说明下面三个方法的使用
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<AA> list3 = new ArrayList<>();
List<BB> list4 = new ArrayList<>();
List<CC> list5 = new ArrayList<>();
//如果是 List<?> c , 可以接受任意的泛型类型
printCollection1(list1);
printCollection1(list2);
printCollection1(list3);
printCollection1(list4);
printCollection1(list5);
//List<? extends AA> c: 表示 上限, 可以接受 AA 或者 AA 子类
// printCollection2(list1);//×
// printCollection2(list2);//×
printCollection2(list3);//√
printCollection2(list4);//√
printCollection2(list5);//√
//List<? super AA> c: 支持 AA 类以及 AA 类的父类, 不限于直接父类
printCollection3(list1);//√
//printCollection3(list2);//×
printCollection3(list3);//√
//printCollection3(list4);//×
//printCollection3(list5);//×
}
// List<?> 表示 任意的泛型类型都可以接受
public static void printCollection1(List<?> c) {
for (Object object : c) { // 通配符, 取出时, 就是 Object
System.out.println(object);
}
}
//
//? extends AA 表示 上限, 可以接受 AA 或者 AA 子类
public static void printCollection2(List<? extends AA> c) {
for (Object object : c) {
System.out.println(object);
}
}
// ? super 子类类名 AA:支持 AA 类以及 AA 类的父类, 不限于直接父类,
public static void printCollection3(List<? super AA> c) {
for (Object object : c) {
System.out.println(object);
}
}
}
class AA {
}
class BB extends AA {
}
class CC extends BB {
}