泛是什么意思?
泛就是非特指,例如英语的a,the是特指。
泛表现我们所看见的了解的,例如继承。
我说动物能跑,但没说具体哪种哪只叫什么,这就是泛。
泛是相对概念,相对更具体的可以是泛。
1.泛举例
1例子1
ArrayList<Integer> integerList = new ArrayList<Integer>();
泛型就是编写模板代码来适应任意类型;
泛型的好处是使用时不必对类型进行强制转换,它通过编译器对类型进行检查;
注意泛型的继承关系:可以把ArrayList<Integer>向上转型为List<Integer>(T不能变!),但不能把ArrayList<Integer>向上转型为ArrayList<Number>(T不能变成父类)。
特别: ArrayList<Integer>和ArrayList<Number>两者完全没有继承关系。
只是Integer继承Number
泛型可以用E或者其他字母泛指类型
2例子2
导包的通配符*
正则表达式的通配符*
等等通配
3.例子3
使用泛型时,把泛型参数
<T>
替换为需要的class类型,例如:ArrayList<String>
,ArrayList<Number>
等;可以省略编译器能自动推断出的类型,例如:
List<String> list = new ArrayList<>();
;不指定泛型参数类型时,编译器会给出警告,且只能将
<T>
视为Object
类型;可以在接口中定义泛型类型,实现此接口的类必须实现正确的泛型类型。
2.自定义泛型
编写泛型时,需要定义泛型类型<T>
;也可以是M等等其他字母,没有具体意义。
静态方法不能引用泛型类型<T>
,必须定义其他类型(例如<K>
)来实现静态泛型方法;
泛型可以同时定义多种类型,例如Map<K, V>
。
/**
* 自定义类型
* 当你没有传递过来的时候 T 就代表了 Obj类型
* @param <T>
*/
public class Page<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
package com.hzit.list;
import com.hzit.model.Page;
public class Demo3 {
public static void main(String[] args) {
Page<String> stringPage = new Page<>();
stringPage.getT();
}
}
1.普通泛型方法(易理解)
不使用泛型构造函数
public class MainClass {//5.2
public static void printArray(Integer[] inputArray) {
for (Integer element : inputArray){
System.out.printf("%s ", element);
System.out.println();//换行
}
}
public static void printArray(Double[] inputArray) {
for (Double element : inputArray){
System.out.printf("%s ", element);
System.out.println();
}
}
public static void printArray(Character[] inputArray) {
for (Character element : inputArray){
System.out.printf("%s ", element);
System.out.println();
}
}
public static void main(String args[]) {
Integer[] integerArray = { 1, 2, 3, 4, 5, 6 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
Character[] characterArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println("输出整型数组:");
printArray(integerArray);
System.out.println("\n输出双精度型数组:");
printArray(doubleArray);
System.out.println("\n输出字符型数组:");
printArray(characterArray);
}
}
使用泛型构造函数
public class MainClasst {
public static void main(String args[]){
Integer[] integerArray = { 1, 2, 3, 4, 5, 6 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
Character[] characterArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println("输出整型数组:");
printArray(integerArray);
System.out.println("\n输出双精度型数组:");
printArray(doubleArray);
System.out.println("\n输出字符型数组:");
printArray(characterArray); }
//泛型
public static <E> void printArray(E[] inputArray){ //E也可以是T,等等字母
//输出
for(E element : inputArray){
System.out.printf("%s ",element);
System.out.println();
}
System.out.println();
}
}
2.静态泛型方法
public class Pair<T> {
private T first;
private T last;
public Pair(T first, T last) {
this.first = first;
this.last = last;
}
public T getFirst() { ... }
public T getLast() { ... }
// 静态泛型方法应该使用其他类型区分:
public static <K> Pair<K> create(K first, K last) {
return new Pair<K>(first, last);
}
}
static
修饰符后面加一个<T>
3.多个泛型类型
public class Pair<T, K> {
private T first;
private K last;
public Pair(T first, K last) {
this.first = first;
this.last = last;
}
public T getFirst() { ... }
public K getLast() { ... }
}
擦拭法
擦拭法 - 廖雪峰的官方网站研究互联网产品和技术,提供原创中文精品教程
https://www.liaoxuefeng.com/wiki/1252599548343744/1265104600263968
所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的。
即,
Java使用擦拭法实现泛型,导致了:
- 编译器把类型
<T>
视为Object
; - 编译器根据
<T>
实现安全的强制转型。
* 当你没有传递过来的时候 T 就代表了 Obj类型
泛型继承(以下例子不会有指代不明)子类反射可用
擦拭法决定了泛型
<T>
:
- 不能是基本类型,例如:
int
;- 不能获取带泛型类型的
Class
,例如:Pair<String>.class
;- 不能判断带泛型类型的类型,例如:
x instanceof Pair<String>
;- 不能实例化
T
类型,例如:new T()
。泛型方法要防止重复定义方法,例如:
public boolean equals(T obj)
;子类可以获取父类的泛型类型
<T>
。