泛型详细解析,泛型的使用与泛型擦除、桥接方法、堆污染

1.泛型的定义

Java泛型(Generic)是J2SE1.5中引入的一个新特性,其本质是参数化类型,也就是说操作的数据类型被指定为一个参数(Type Paramcter) 这种参数类型可以用在类,接口和方法的创建中

泛型类:public class Demo<T> {} ,T表示未知类型。

泛型接口:public interface ImplDemo<T,V>{} ,和定义类一样(接口就是一个特殊类)。

泛型方法:public <T> void demo1(T name){System.out.println(name);} , public <T> T demo2(T t){ return t;}

2.桥接方法和类型擦除

泛型的类型擦除(泛型只在编译阶段有效,泛型类型在逻辑上可看成是多个不同的类型,但是其实质都是同一个数据类型,编译之后程序会采取去泛型化的措施)

问题一:list.getClass() == strList.getClass() 输出的结果是什么?

@Test
public vodi m01() {
    List list = new ArrayList();
    List<String> strList = new ArrayList<>();
    System.out.println(list.getClass() == strList.getClass());
}

答案:输出的结果是true。直接打开命令行工具,使用javap varbose方法显示字节码文件,可直接看出是一样的

问题二:在编译之后使用反射重新非指定的List类型是否可以?

@Test
public void m02() throw Exception {
    List<String> strList = new ArrayList<>();
    strList.add("abc"); // 直接添加指定的同类型数据可行
    strList.add("abcd");
    strList.add(new Object()) // 直接添加不同指定类型的数据不可行,Object为add方法指定的类型
    System.out.println("strList.size" + strList.size());
    System.out.println("----------------------------");
    
    // 在编译完之后, 使用反射添加非指定类型数据
    Class<? extends List> clazz = strList.getClass();
    Method addMethod = clazz.getDeclaredMethod("add",Object.class);
    addMethod.invoke(strList,new Object()); // 可行
    
    System.out.println(strList.size());
}

问题三:堆污染:当一个可变泛型参数指向一个无泛型参数时,可能发生的一种现象

public class Pollution {
    public static void main(String args[]) {
        Set set = new Set();
 //       set.add("abc");
        varMethod(set);
        Iteartor<String> iteartor = set.Iteartor();
        while(iteartor.hasNext()) {
            String str = iteartor.next();
        }
    }
    
    public static void varMethod(Set<Integer> set) {
        set.add(123);
        System.out.println(set.size());
    }
}

答案:会产生堆污染

桥接方法(JDK1.5引入泛型后,为了使Java的泛型方法生成的字节码和1.5版本前的字节码相兼容,由编译器自动生成的方法。是伴随着泛型方法一起出现的,目的是父类实现泛型方法,子类实现具体类型的同一方法,在多态的时候能够实现子类具体类型的方法)

public interface SuperClass<T> {
    T m01(T param);
}

// 实现泛型接口
public class SubClass implements SuperClass<String> {
    public String m01(String param) {return param+"---";}
}

public class BridgeMethodTest {
    public static void main(String[] args) {
        SuperClass clazz = new SubClass() // 多态,父类的引用指向子类的实现
        System.out.println("123abc"); // 能编译,能执行   
        System.out.println(new Object()); // 能编译,不能执行(因为桥接方法的调用还是类中的String类型的m01方法)
        
        Method m = clazz.getClass().getDeclaredMethod("mo1",Object.class);
        System.out.println(m.isBridge());
    }
}

控制台使用javap varbose 命令显示SubClass字节码,会显示有两个m01方法,下面这个是泛型的桥接方法,还有一个是类中的String类型m01方法

3.通配符

泛型的通配符包含三种边界:

无界:?<?>

上界:<? extends E>

下界:<? super E>

泛型的作用:用于编译检查,保证类型的安全,避免强制转换的硬编码,增加调用代码的重用性

4.泛型的使用

泛型的具体使用:

泛型和成员属性一样,需要先声明才能使用,泛型的声明采用<> 进行声明,声明一般约定采用单个大写字母表示,常用的用K E T V 等等

泛型类

泛型方法:

实体方法可以使用在类中定义的泛型或者方法中定义的泛型

静态方法不可以使用在类中定义的泛型,只能使用在静态方法上定义的泛型

泛型接口

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Building-ui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值