原文章地址:https://www.jianshu.com/p/986f732ed2f1
泛型
1. 泛型存在的意义?
泛型:即“参数化类型”,将类型由原来的具体类型参数化,然后再使用/调用时传入具体的类型。
意义:
1.适用于多种数据类型执行相同的代码
2. 泛型中的类型在使用时指定,不需要强制类型转换
2. 泛型类,泛型接口,泛型方法如何定义?
- 泛型类定义:
public class GenericClass<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static void main(String[] args) {
GenericClass<String> genericClass = new GenericClass<>();
genericClass.setData("Generic Class");
System.out.println(genericClass.getData());
}
}
- 泛型接口定义
public interface GenericInterface<T> {
T getData();
}
- 泛型接口实现方式1:泛型接口实现类+泛型类型
public class GenericInterfaceImpl<T> implements GenericInterface<T>{
private T data;
private void setData(T data){
this.data = data;
}
@Override
public T getData() {
return data;
}
public static void main(String[] args) {
GenericInterfaceImpl<String> genericInterface = new GenericInterfaceImpl<>();
genericInterface.setData("Generic Interface1");
System.out.println(genericInterface.getData());
}
}
- 泛型接口实现方式2:泛型接口实现类 + 具体类型
public class GenericInterfaceImpl2 implements GenericInterface<String> {
private String data;
private void setData(String data){
this.data = data;
}
@Override
public String getData() {
return data;
}
public static void main(String[] args) {
GenericInterfaceImpl2 genericInterfaceImpl = new GenericInterfaceImpl2();
genericInterfaceImpl.setData("Generic Interface");
System.out.println(genericInterfaceImpl.getData());
}
}
- 泛型方法定义
public class GenericMethod {
private static int add(int a,int b){
System.out.println(a + "+" + b + "=" + (a+b));
return a + b;
}
private static <T> T genericAdd(T a,T b){
System.out.println(a + "+" + b + "=" + a + b);
return a;
}
public static void main(String[] args) {
System.out.println("return: " + GenericMethod.add(1,2));
System.out.println("return: " + GenericMethod.genericAdd("a","b"));
}
}
3. 如何限定类型变量?
- 对类进行类型限定:
public class TypeLimitForClass<T extends List & Serializable>
public class TypeLimitForClass<T extends List & Serializable> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static void main(String[] args) {
ArrayList<String> stringArrayList = new ArrayList<>();
stringArrayList.add("A");
stringArrayList.add("b");
ArrayList<Integer> integerArrayList = new ArrayList<>();
integerArrayList.add(1);
integerArrayList.add(2);
TypeLimitForClass<ArrayList> typeLimitForClass = new TypeLimitForClass<>();
typeLimitForClass.setData(stringArrayList);
TypeLimitForClass<ArrayList> typeLimitForClass1 = new TypeLimitForClass<>();
typeLimitForClass1.setData(integerArrayList);
}
}
- 对方法进行类型限定:
public static <T extends Comparable<T>> T getMin
public class TypeLimitForMethod {
public static <T extends Comparable<T>> T getMin(T a,T b){
return (a.compareTo(b) < 0) ? a : b;
}
public static void main(String[] args) {
System.out.println(TypeLimitForMethod.getMin(1,5));
System.out.println(TypeLimitForMethod.getMin("a","b"));
}
}
4. 泛型中使用的约束和局限性有哪些?
1、泛型不能被实例化
public class GenericRestrict1<T> {
static class NormalClass{
}
private T data;
public void setData(){
this.data = new T();//Type parameter 'T' cannot be instantiated directly
}
}
2、静态变量不能是泛型类型,但是静态泛型方法是可以的
private static T data1;//cannot be referenced from a static context
public static <K> K getData(K k){
return k;
}
3、基本类型无法作为泛型类型
GenericRestrict1<int> restrict2 = new GenericRestrict1<int>();//Type argument cannot be of primitive type
4、无法使用instanceof关键字或==判断泛型类的类型
restrict1 instanceof GenericRestrict1<String> //Illegal generic type for instanceof
5、泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的
NormalClass normalClassA = new NormalClass();
NormalClass normalClassB = new NormalClass();
System.out.println(normalClassA == normalClassB);//false
System.out.println(restrict1.getClass() == integerGenericRestrict1.getClass());//true
System.out.println(restrict1.getClass());
System.out.println(integerGenericRestrict1.getClass());
6、泛型数组可以声明但无法实例化
GenericRestrict1<String>[] genericRestrict1s;//可以被声明
//genericRestrict1s = new GenericRestrict1<String>[10]; 不可声明为泛型
genericRestrict1s = new GenericRestrict1[10];
genericRestrict1s[0] = restrict1;
7、泛型类不能继承Exception或者Throwable
private class MyGenericException<T> extends Exception{
}
private class MyGenericThrowable<T> extends Throwable{
}
public <T extends Exception> void getExecption(T t){
try {
}catch (T e){
}
}
8、不能捕获泛型类型限定的异常但可以将泛型限定的异常抛出
5. 泛型类型的继承规则是什么?
1、对于泛型参数是继承关系的泛型类之间是没有继承关系的
public class GenericInherit<T> {
private T data1;
private T data2;
public T getData1() {
return data1;
}
public void setData1(T data1) {
this.data1 = data1;
}
public T getData2() {
return data2;
}
public void setData2(T data2) {
this.data2 = data2;
}
public static <V> void setData2(GenericInherit<Father> data2){
}
public static void main(String[] args) {
Father father = new Father();
Son son = new Son();
GenericInherit<Father> fatherGenericInherit = new GenericInherit<>();
GenericInherit<Son> sonGenericInherit = new GenericInherit<>();
SubGenericInherit<Father> fatherSubGenericInherit = new SubGenericInherit<>();
SubGenericInherit<Son> sonSubGenericInherit = new SubGenericInherit<>();
father = new Son();
setData2(fatherGenericInherit);
setData2(fatherSubGenericInherit);
//setData2(sonGenericInherit); ERROR
//泛型类的继承关系在使用中同样会受到泛型类型的影响
setData2(sonSubGenericInherit);
}
}
2、泛型类可以继承其它泛型类,例如: public class ArrayList extends AbstractList
/**
* 泛型类可以继承其它泛型类,例如: public class ArrayList<E> extends AbstractList<E>
*/
fatherGenericInherit = new SubGenericInherit<Father>();
3、泛型类的继承关系在使用中同样会受到泛型类型的影响
6. 泛型中的通配符类型是什么?
public class GenericByWildcard {
private static void print(GenericClass<Fruit> fruitGenericClass) {
System.out.println(fruitGenericClass.getData().getType());
}
private static void use() {
GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
print(fruitGenericClass);
GenericClass<Orange> orangeGenericClass = new GenericClass<>();
//传递的泛型之间是继承关系的泛型类之间是没有继承关系的
//print(orangeGenericClass); ERROR
}
/**
* <? extends Fruit>规范了泛型的上限,即继承自Fruit的类都接受
*
* @param superGenericClass
*/
private static void printExtend(GenericClass<? extends Fruit> superGenericClass) {
System.out.println(superGenericClass.getData().getType());
}
private static void useExtend() {
GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
printExtend(fruitGenericClass);
GenericClass<Apple> appleGenericClass = new GenericClass<>();
printExtend(appleGenericClass);
GenericClass<Food> foodGenericClass = new GenericClass<>();
//food超过了fruit会报错
//printExtend(foodGenericClass);
GenericClass<? extends Fruit> genericClass = new GenericClass<>();
Apple apple = new Apple();
Fruit fruit = new Fruit();
/**
* get时编译器可以肯定返回的是个X,set时编译器无法知道参数是X的哪个子类
*/
//genericClass.setData(apple);
//genericClass.setData(fruit);
fruit = genericClass.getData();
}
public static void printSuper(GenericClass<? super Apple> genericClass) {
System.out.println(genericClass.getData());
}
public static void useSuper() {
GenericClass<Food> foodGenericClass = new GenericClass<>();
printSuper(foodGenericClass);
GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
printSuper(fruitGenericClass);
GenericClass<Apple> appleGenericClass = new GenericClass<>();
printSuper(appleGenericClass);
//HongFuShi是Apple的子类所以类型不匹配
GenericClass<HongFuShi> hongFuShiGenericClass = new GenericClass<>();
// printSuper(hongFuShiGenericClass);
GenericClass<? super Apple> supperAppleGenericClass = new GenericClass<>();
supperAppleGenericClass.setData(new Apple());
supperAppleGenericClass.setData(new HongFuShi());
/*
* ? super X 表示类型的下界,参数类型是X的超类
* 那么可以肯定的说,get方法返回的一定是X的一个超类,具体是哪个不清楚
* 但是可以肯定的说,Object一定是他的超类,所以get方法返回Object
* 编译器是可以确定知道的,对于set方法来说,编译器不知道它需要的确切类型,但是X和X的子类可以安全的转型为X
* 主要用于安全的写入数据,可以写入X及其子类型
* */
Object data = supperAppleGenericClass.getData();
}
/**
* 没有指定的限定符
* @param genericClass
*/
public static void printNonLimit(GenericClass<?> genericClass){
System.out.println(genericClass.getData());
}
public static void useNonLimit(){
GenericClass<Food> foodGenericClass = new GenericClass<>();
printNonLimit(foodGenericClass);
GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
printNonLimit(fruitGenericClass);
GenericClass<Apple> appleGenericClass = new GenericClass<>();
printNonLimit(appleGenericClass);
GenericClass<?> genericClass = new GenericClass<>();
// genericClass.setData(foodGenericClass);
// genericClass.setData(new Object());
Object data = genericClass.getData();
}
}
- 如何获取泛型的参数类型?
8. 虚拟机是如何实现泛型的?
Java泛型是Java1.5之后才引入的,为了向下兼容。Java采用了C++完全不同的实现思想。Java中的泛型更多的看起来像是编译期用的
Java中泛型在运行期是不可见的,会被擦除为它的上级类型。如果是没有限定的泛型参数类型,就会被替换为Object.即泛型擦除
9. 在日常开发中是如何运用泛型的?
1.泛型解析JSON数据封装
未完待续……