泛型

泛型

使用泛型创建实例时,编译器来负责转型,确保类型正确

  • 代码的安全性检查提前到编译期
  • 对传入值进行编译期检查,对传递出去的值自动转型,简化代码
  • 泛型参数不能为基本类型
  • 类型推断只对赋值操作有效,其他操作编译器不执行类型推断
  • 相比于使用Object,泛型可以暂不指定类型,由编译器负责转型
泛型类

在类名后使用尖括号来指定类持有什么类型的对象,创建对象时要指定参数类型,静态方法要使用泛型能力必须声明为泛型方法

public class A<K,V>{
	K key;
	V val;
	public K getKey(){
		return key;
	}
	public void setKey(K key){
		this.key=key;
	}
}
泛型方法

定义泛型方法是在方法返回类型前定义泛型参数列表,泛型方法独立于泛型类,使用泛型方法通常不必指定参数类型(显示声明:类名/this.<类型> print() )

public <T> void print(T val){
	System.out.println(val);
}
泛型擦除

编译后具体类型被擦除, 在泛型代码内部无法获得任何有关泛型参数类型的信息

public class Base<T> {
    public T value;
    public Base(){}
    public Base(T v){
        value=v;
    }
    public T getValue(){
        return value;
    }
    public void setValue(T value){
        this.value=value;
    }
}

未设置边界
参数类型被擦除到Object

public static void main(String[] args) {
    Base<String> base = new Base<>();
    base.setValue("king");
}

在这里插入图片描述
设置边界
语法<T extends ClassA & InterfaceA & interfaceB>,设置边界也是对泛型擦除的一种补偿机制,使参数类型能够调用部分方法

class Test{}
class A extends Test{}
//设置泛型类型T的上界Test
public class Base<T extends Test> {
	······
}
public static void main(String[] args) {
    Base<A> base = new Base<>();
    base.setValue(new A());
}

可以看出参数类型被擦除到Test
在这里插入图片描述

协变与逆变

两个类型之间建立某种类型的向上转型关系

  • 数组是协变的(可将子类型引用赋值给基类型)
  • 泛型是不变的(类型不同直接编译时报错)

因为泛型是不变的,当泛型需要使用协变和逆变时则需引入通配符<?>
协变实现:<? extends A>,不可写入,可获得A及其父类
逆变实现:<?super A>,可写入A及其子类,不可获得

泛型的获取

泛型的擦除是针对Code中字节码的,编译后在signature属性中还是保留了泛型参数类型,我们可以通过反射获取对应的参数类型。

LocalVariableTypeTable:本地变量类型表存在于Code属性中,提供变量类型的签名信息
Signature:存在类结构、字段表、方法表中,记录泛型签名信息
在这里插入图片描述

Type接口
标识接口,所有类型的通用超级接口。 这些包括原始类型,参数化类型,数组类型,类型变量和原始类型。

public interface Type {
}

ParameterizedType 接口
参数化类型接口

public interface ParameterizedType extends Type {
    //返回此类型的实际类型参数的数组,如A<String>返回String
    Type[] getActualTypeArguments();
	//返回当前声明的类型,如A<String>返回A
    Type getRawType();
	//返回所属类型
    Type getOwnerType();
}

常见获取方法

public static void main(String[] args) {
        Base<String,Integer> map = new Base<String,Integer>(){};
        //使用匿名内部类获得对象父类持有的泛型类型
        Type genericSuperclass = map.getClass().getGenericSuperclass();
        if(genericSuperclass instanceof ParameterizedType){
            Type[] types = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
            System.out.println(Arrays.toString(types));
        }
        try {
            //获得成员变量的参数类型   List<String> list;
            Base<String,Integer> map2 = new Base<>();
            Field list = map2.getClass().getDeclaredField("list");
            Type genericType = list.getGenericType();
            if(genericType instanceof ParameterizedType){
                Type[] types = ((ParameterizedType) genericType).getActualTypeArguments();
                System.out.println(Arrays.toString(types));
            }
            //获得方法的参数类型 public T test(ArrayList<String> list){}
            Method method = map2.getClass().getDeclaredMethod("test", ArrayList.class);
            //传入参数类型
            Type[] genericParameterTypes = method.getGenericParameterTypes();
            for(Type type:genericParameterTypes){
                Type[] types = ((ParameterizedType) type).getActualTypeArguments();
                System.out.println(Arrays.toString(types));
            }
            //返回参数类型
            ParameterizedType genericReturnType = (ParameterizedType)method.getGenericReturnType();
            System.out.println(Arrays.toString(genericReturnType.getActualTypeArguments()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

输出结果如下

[class java.lang.String, class java.lang.Integer]
[class java.lang.String]
[class java.lang.String]
[class java.lang.String]

自限定类型 class A<T extends A<T>>,保证类型参数与正在被定义的类相同

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值