一、爲什麼要使用泛型?
當我們在創建某個方法的時候,參數、返回值類型未知,創建某個類中的成員的時候,類型也是未知的,此時我們可以使用泛型,在我們實際調用方法的時候,或者創建具體的類對象的時候,再設置具體的類型。
或者當我們的方法在考慮到複用性的時候使用泛型。例如不同類型參數都可以接受。
二、泛型類
- 在類中聲明泛型
public class GenericClass<T> {
private T data;
public void setData(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
- 創建泛型類對象
GenericClass<String> genericClass = new GenericClass<>();
genericClass.setData("泛型類");
System.out.println(genericClass.getData());
三、泛型接口
(1)創建泛型接口
public interface GenericInterface<T> {
T getData();
void setData(T t);
}
(2)實現泛型接口
public class GenericInterfaceImpl<T> extends implements GenericInterface<T> {
private T t;
@Override
public T getData() {
return t;
}
@Override
public void setData(T t) {
this.t = t;
}
}
(3)創建泛型接口對象
GenericInterface<String> genericInterface = new GenericInterfaceImpl<>();
genericClass.setData("泛型接口");
System.out.println(genericClass.getData());
四、泛型類的繼承
(1)創建泛型父類
public abstract class GenericAbstarctClass<T> {
abstract T getData();
abstract void setTata(T t);
}
(2)泛型子類的繼承
package com.it.test.generic;
public class GenericClassExtends<T> extends GenericAbstarctClass<T> {
private T t;
@Override
T getData() {
return t;
}
@Override
void setTata(T s) {
this.t = s;
}
}
(3)泛型類繼承對象的創建
GenericAbstarctClass<String> genericAbstarctClass = new GenericClassExtends<>();
genericAbstarctClass.setTata("繼承使用泛型");
System.out.printf(genericAbstarctClass.getData());
- 注意
我們來看以下代碼,User繼承了Person,但是userGener 和personGener 是兩個獨立的關係,不存在繼承關係。而GenericClassExtends和GenericAbstarctClass纔是繼承關係
GenericAbstarctClass<User> userGener = new GenericClassExtends<>();
GenericAbstarctClass<Person> personGener = new GenericClassExtends<>();
五、泛型方法
(1)創建泛型方法
/**
* 泛型方法
*
* @param t
* @param <T>
* @return
*/
static <T> T function(T t) {
return t;
}
(2)使用泛型方法
此時function方法的參數和返回類型都是泛型,因此此時可以傳遞任意類型。
System.out.println(function("泛型方法"));
六、限定類型變量
當我們希望設置泛型的類型必須要包含某個類的行爲時候,可以使用限定類型變量extends。
例如我們希望泛型類中設置的泛型必須包含compareTo方法和add方法
此時我們讓我們的泛型<T extends ArrayList & Comparable>。如果extends中包含了類,則類放在第一位,接口放在後面,接口可以有多個,類和接口直接都用&符號連接。
如下代碼:
/**
* 如果我們希望泛型包含指定類的方法
* 我們需要添加限定類型變量
* extends指定派生類,當有多個派生類的時候
* 第一個爲類,&符號後面爲接口
*
* @param <T>
*/
public class GenericClass2<T extends ArrayList & Comparable> {
int function(T t) {
return t.compareTo("a");
}
void function2(T t) {
System.out.println("add= "+t.add("a"));
}
}
七、通配符類型
通配符類型使用:
? extends Person 限制了類型的上界
? super Person 限制了類型的下界
(1)personGenericType 和userGenericType 中雖然Student繼承了User。但是調用function3(GenericType<Person> type)方法的時候,只能接受personGenericType 。不能接受userGenericType 。因爲userGenericType 和personGenericType 不存在繼承關係。
(2)所以我們需要通配符? extends Person 或者? super Person
- ? extends Person 的意思指的是GenericType類設置的泛型只要是Person 以下的類都可以接受
- ? super Person 的意思指的是GenericType類設置的泛型只要是Person 之上的類都可以接受
我們可以看function4和function5方法
如下代碼:
static void function5(GenericType<? super User> type) {
//? super 可以獲取數據
type.setData(new User());
type.setData(new Student());
}
static void function3(GenericType<Person> type) {
}
static void function4(GenericType<? extends Person> type) {
// //? super 可以設置數據
Person person = type.getData();
}
GenericType<Person> personGenericType = new GenericType<>();
GenericType<User> userGenericType = new GenericType<>();
GenericType<Student> studentGenericType = new GenericType<>();
//類型匹配
function3(personGenericType);
//類型不匹配,不能編譯
//類型必須是Person的子類
function3(userGenericType);
//使用? extends通配符
//類型匹配
function4(personGenericType);
//類型匹配
function4(userGenericType);
//類型匹配
function5(personGenericType);
//類型不匹配類型必須是User的超類
function5(studentGenericType);
八、泛型中的一些約束
(1)不能實例化泛型變量
(2)泛型類中的泛型,不能使用在靜態方法上
(3)泛型方法可以使用在靜態方法中
public class Restric<T> {
/**
* 不能實例化泛型變量
*
* @return
*/
T getData() {
return new T();
}
/**
* 泛型類中的泛型,不能使用在靜態方法上
*
* @param t
* @return
*/
static T function(T t) {
return t;
}
/**
* 泛型方法可以使用在靜態方法中
* @param e
* @param <E>
* @return
*/
static <E> E funtionc2(E e) {
return e;
}
}
(4)泛型不能使用在基本類型中
(5)泛型不能使用instance of
if(genericAbstarctClass instanceof GenericAbstarctClass<String> ){
}
(6) 可以聲明泛型數組,但是不能實例化
//沒問題
GenericAbstarctClass<String>[]arrays;
//有問題
GenericAbstarctClass<String>[]arrays2 = new GenericAbstarctClass<String>[10];
(7)泛型類不能派生Excetion/Throw
class GenericInterfaceImpl<T> extends Exception 有問題
(8)不能捕獲泛型類型的異常,可以拋出泛型異常
/**
* 不能捕獲泛型類型的異常
*
* @param <T>
* @return
*/
<T extends Exception> T function() {
try {
} catch (T e) {
}
}
/**
* 可以拋出泛型異常
*
* @param e
* @param <T>
* @return
* @throws T
*/
<T extends Exception> T function2(T e) throws T {
throw e;
}
九、虛擬機如何實現泛型
泛型擦除。字節碼中實際上是擦除了泛型,而在實際執行期間是根據泛型進行了強轉、在虛擬機有有一個變量實現了弱記憶功能,記住泛型的類型。
通過匿名內部類來獲取泛型類型
package com.example.myapplication;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 自定義一個泛型類
* @param <T>
*/
public class TypeClass<T> {
public Type getType() {
//獲取泛型類型
Type type = getClass().getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) type;
//因爲泛型可能有多個,所以是一個數組
Type[] types = parameterizedType.getActualTypeArguments();
//測試獲取第一個泛型類型
return types[0];
}
}
//通過反射獲取泛型類型
//通過匿名內部類來實現,獲取泛型的類型
TypeClass<String> typeClass = new TypeClass<String>() {
};
Log.e("ResultActivity", "getType = "+typeClass.getType());