一、为什么要使用泛型?
当我们在创建某个方法的时候,参数、返回值类型未知,创建某个类中的成员的时候,类型也是未知的,此时我们可以使用泛型,在我们实际调用方法的时候,或者创建具体的类对象的时候,再设置具体的类型。
或者当我们的方法在考虑到复用性的时候使用泛型。例如不同类型参数都可以接受。
二、泛型类
- 在类中声明泛型
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());
网友评论