目录
1. 什么是 Java 泛型(generics)?
泛型,即参数化类型。
变量可以是参数,实际使用时,再确定它的值。那么,类型,也可以是一个参数,实际使用时,再确定它到底是什么类型。
2. 经典使用场景
Java 的集合类中对泛型的使用极为广泛,如 List,Set,Map等。
举个例子:
class Scratch {
public static void main(String[] args) {
// 未指定 List 内的类型
List arrayList = new ArrayList();
arrayList.add("aaaa");
arrayList.add(11);
for(int i=0; i<arrayList.size();i++){
String item = (String)arrayList.get(i);
System.out.println(item);
}
System.out.println("end");
}
}
此时的输出结果是:
第一个 String 元素“aaaa”被正确输出,第二个 int 元素被强制转换为 String 类型时,会报异常。
但是如果将强制转换去掉,直接输出,就不会报错。
for(int i=0; i<arrayList.size();i++){
// String item = (String)arrayList.get(i);
System.out.println(arrayList.get(i));
}
在没有指定类型时,ArrayList变量可以存放任意类型的值,且不会报错。
但是如果在定义ArrayList变量时,指定类型,就只能 add 指定类型的变量。(编译期间就会检查 add 的是否是指定类型的值)
3. 特性
泛型只在编译阶段有效。
在编译之后程序会采取去泛型化的措施。
4. 泛型的使用
泛型的使用包括:泛型类,泛型接口,泛型方法。
4.1 泛型类
基本写法:
//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,须指定T的具体类型
public class Generic<T>{
//key这个成员变量的类型为T, T的类型由外部指定
private T key;
public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
return key;
}
}
4.2 泛型接口
泛型接口与泛型类的定义及使用基本相同。
泛型接口常被用在各种类的生产器中。
基本写法:
//定义一个泛型接口
public interface Generator<T> {
public T next();
}
实现泛型接口的类,可以传入泛型实参,也可以不传入泛型实参:
// 不传入泛型实参
class FruitGenerator<T> implements Generator<T>{
@Override
public T next() {
return null;
}
}
// 传入泛型实参
public class FruitGenerator implements Generator<String> {
private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}
4.3 泛型方法
4.3.1 基本写法
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
IllegalAccessException{
T instance = tClass.newInstance();
return instance;
}
4.3.2 泛型类中的泛型方法
public class GenericFruit {
class Fruit{
@Override
public String toString() {
return "fruit";
}
}
class Apple extends Fruit{
@Override
public String toString() {
return "apple";
}
}
class Person{
@Override
public String toString() {
return "Person";
}
}
class GenerateTest<T>{
public void show_1(T t){
System.out.println(t.toString());
}
//在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型,比如写作E。
public <T> void show_2(T t){
System.out.println(t.toString());
}
}
public static void main(String[] args) {
Apple apple = new Apple();
Person person = new Person();
GenerateTest<Fruit> generateTest = new GenerateTest<Fruit>();
//apple是Fruit的子类,所以这里可以
generateTest.show_1(apple);
//编译器会报错,因为泛型类型实参指定的是Fruit,而传入的实参类是Person
//generateTest.show_1(person);
//使用这两个方法都可以成功
generateTest.show_2(apple);
generateTest.show_2(person);
}
}
4.3.3 泛型类中的静态泛型方法
在泛型类中使用泛型的静态方法时,需要将此静态方法写成泛型方法的形式,否则编译报错。
public class StaticGenerator<T> {
public static <T> void show(T t){
*****
}
}
4.3.4 可变参数泛型方法
当泛型方法使用可变参数时:
public <T> void printMsg( T... args){
for(T t : args){
System.out.println(t);
}
}