文章目录
- 1. 泛型入门
- 1.1 定义简单泛型类
- 1.2 泛型方法
- 1.3 限定类型变量
- 2. 擦除和转换
- 2.1 类型擦除
- 3. 类型通配符
- 3.1 通配符上限
- 3.2 通配符下限
- 3.3 例子
- 4. java的Type
- 4.1 UML总览
1. 泛型入门
泛型的英文名Generic,java5以后,引入参数化类型(parameterized type)概念,允许在创建集合时指定集合元素的类型。Java 的 参 数 化 类 型 被 称 为 泛 型(Generic)。
代码示例:
public static void main(String[] args) {// 指定类型为StringList<String> list = new ArrayList<>();list.add("dsf");// 类型不符,报错list.add(1);}
1.1 定义简单泛型类
public class Pair<T> {private T first;private T second;public Pair() {}public Pair(T min, T max) {this.first = min;this.second = max;}public T getFirst() {return first;}public void setFirst(T first) {this.first = first;}public T getSecond() {return second;}public void setSecond(T second) {this.second = second;}
}
类型变量T用<>括起来,使用大写形式。在java中,使用E表示集合中的元素,K和V表示键和值,T(U,S)表示任意类型。
使用示例:
public class ArrayAlg {public static Pair<String> minmax(String[] arr) {if (arr == null || arr.length == 0) {return null;}String min = arr[0];String max = arr[0];for (int i = 0, length = arr.length; i < length; i++) {if (min.compareTo(arr[i]) > 0) {min = arr[i];}if (max.compareTo(arr[i]) < 0) {max = arr[i];}}return new Pair<>(min, max);}}
1.2 泛型方法
public static <T> T getMiddle(T... arr) {return arr[arr.length / 2];}
使用示例:
public static void main(String[] args) {String sdaf = ArrayAlg.getMiddle("123", "sdaf");}
1.3 限定类型变量
public static <T extends Comparable> T min(T[] arr) {if (arr == null || arr.length == 0) {return null;}T min = arr[0];for (int i = 0; i < arr.length; i++) {if (min.compareTo(arr[i]) > 0) {min = arr[i];}}return min;}
限定T是Comparable或Comparable的子类。
2. 擦除和转换
虚拟机没有泛型类型对象,所有对象都是普通类。
2.1 类型擦除
- 如果类型变量没有限定,那么会用原始Object替换T。
上文的Pair类的T没有指定上限。
public static void main(String[] args) {// 限定String类型Pair<String> pair = new Pair<String>("2134","sfsdf");String first = pair.getFirst();// pair2没有指定类型,first1只能知道是ObjectPair pair2 = pair;Object first1 = pair2.getFirst();// 编译报错String first2 = pair2.getFirst();}
- 如果类型变量有限定,那么会用上限t替换T。
public class Apple<T extends Number> {T size;public Apple(T size) {this.size = size;}public T getSize() {return size;}public void setSize(T size) {this.size = size;}
}
public static void main(String[] args) {Apple<Integer> apple = new Apple<>(6);// 这里返回Integer对象Integer size = apple.getSize();// apple2丢失尖括号的类型信息,apple2只能知道Number类型Apple apple2 = apple;Number size1 = apple2.getSize();// 编译报错Integer size2 = apple2.getSize();}
- 步骤
Java编译器编译泛型的步骤:
1.检查泛型的类型 ,获得目标类型
2.擦除类型变量,并替换为限定类型(T为无限定的类型变量,用Object替换)
3.调用相关函数,并将结果强制转换为目标类型。
public static void main(String[] args) {ArrayList<String> arrayString = new ArrayList<String>();ArrayList<Integer> arrayInteger = new ArrayList<Integer>();System.out.println(arrayString.getClass() == arrayInteger.getClass());}
运行结果为true。getClass()总是返回原始类型。
3. 类型通配符
类型通配符: ?,代表任意类型。
3.1 通配符上限
<? extends T>, 意思是需要一个T类型或者T类型的子类。 适用于消费集合元素为主的场景。
public class Animal {
}
Cat继承Animal 。
public class Cat extends Animal {}
public static void handle(List<? extends Animal> list) {for (Animal animal : list) {System.out.println(animal);}// 编译报错,不能添加元素list.add(new Animal());list.add(new Cat());}
3.2 通配符下限
<? super T>,意思是需要一个T类型或者T类型的父类。适用于生产元素为主的场景。
public static void handle2(List<? super Cat> list) {// 只能是Objectfor (Object cat : list) {System.out.println(cat);}// 编译报错for (Cat cat : list) {System.out.println(cat);}list.add(new Cat());}
3.3 例子
public static void main(String[] args) {// 1.继承关系:Object > Animal > Cat > WhiteCatList<Animal> animals = new ArrayList<>();List<Cat> cats = new ArrayList<>();List<WhiteCat> whiteCats = new ArrayList<>();animals.add(new Animal());cats.add(new Cat());whiteCats.add(new WhiteCat());// 2.测试赋值操作// 下一行报错,只能赋值给Cat或Cat之类List<? extends Cat> extendsCatFromAnimal = animals;List<? super Cat> superCatFromAnimal = animals;List<? extends Cat> extendsCatFromCat = cats;List<? super Cat> superCatFromCat = cats;List<? extends Cat> extendsCatFromWhiteCat = whiteCats;// 报错,只能赋值给Cat或Cat的父类List<? super Cat> superCatFromWhiteCat = whiteCats;// 3.测试add方法// 均报错,无法addextendsCatFromCat.add(new Animal());extendsCatFromCat.add(new Cat());extendsCatFromCat.add(new WhiteCat());// 下一行报错,只能添加Cat或Cat的子类superCatFromCat.add(new Animal());superCatFromCat.add(new Cat());superCatFromCat.add(new WhiteCat());// 4.测试get方法// 所有super操作都能够返回元素,不过泛型丢失,只能是Object类型Object object = superCatFromAnimal.get(0);Object object2 = superCatFromCat.get(0);Object object3 = superCatFromWhiteCat.get(0);// 均可以返回Cat cat = extendsCatFromAnimal.get(0);Cat cat1 = extendsCatFromCat.get(0);// 报错,虽然WhiteCat继承Cat,但类型擦除之后是不知道的WhiteCat cat2 = extendsCatFromWhiteCat.get(0);}