栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java泛型-类型擦除

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java泛型-类型擦除

文章目录
  • 1.泛型和类型擦除
  • 2.变量类型擦除
    • 2.1 无限制类型擦除
    • 2.2 有限制类型擦除
  • 3.方法类型擦除
    • 3.1 无限制类型擦除
    • 3.2 有限制类型擦除
    • 3.3 桥接方法


1.泛型和类型擦除 泛型:泛型是java 5中引入的一个新特性,允许我们在定义类和接口的时候使用类型参数,类型参数在使用时用具体的类型替换,所以为了兼容java 5之前的版本,引入了类型擦除
类型擦除:编译器在编译时擦除了所有跟类型参数相关的信息,所以在运行时访问不到类型参数相关的信息,编译器在编译时会将类型参数转换为原始类型,目的就是为了兼容java 5之前的版本,类型擦除主要的过程是首先移除所有类型参数,然后用其最顶级的父类型替换

2.变量类型擦除 2.1 无限制类型擦除

编译器在编译时将类型参数T替换为了Object,所以在运行时我们打印成员变量t的类型时访问到的是Object类型

import java.lang.reflect.Field;

public class Test01 {
    public static void main(String[] args) {
        // 无限制类型擦除
        Class a = A.class;
        Field[] fields = a.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName()+":"+field.getType().getSimpleName()); // t:Object
        }
    }
}

class A {
    T t;
}
2.2 有限制类型擦除

编译器在编译时将类型参数T替换为了Number(由于T extends Number,所以T的上限是Number,所以T最顶级的父类型是Number),所以在运行时我们打印成员变量t的类型时访问到的是Number类型

import java.lang.reflect.Field;

public class Test02 {
    public static void main(String[] args) {
        // 有限制类型擦除
        Class b = B.class;
        Field[] fields = b.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName()+":"+field.getType().getSimpleName()); // t:Number
        }
    }
}

class B {
    T t;
}
3.方法类型擦除 3.1 无限制类型擦除

编译器在编译时将类型参数K替换为了Object,所以在运行时我们打印成员方法fun的返回值类型时访问到的是Object类型

import java.lang.reflect.Method;

public class Test03 {
    public static void main(String[] args) {
        // 无限制类型擦除
        Class c = C.class;
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName()+":"+method.getReturnType().getSimpleName()); // fun:Object
        }
    }
}

class C {
    T t;

    public  K fun(K k) {
        return null;
    }
}
3.2 有限制类型擦除

编译器在编译时将类型参数K替换为了Number(由于K extends Number,所以K的上限是Number,所以K最顶级的父类型是Number),所以在运行时我们打印成员方法fun的返回值类型时访问到的是Number类型

import java.lang.reflect.Method;

public class Test04 {
    public static void main(String[] args) {
        // 有限制类型擦除
        Class d = D.class;
        Method[] methods = d.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName()+":"+method.getReturnType().getSimpleName()); // fun:Number
        }
    }
}

class D {
    T t;

    public  K fun(K k) {
        return null;
    }
}
3.3 桥接方法

首先我们来分析以下代码,左边定义了Info接口和对应的实现类,实现类指定泛型具体类型为Integer并且重写了抽象方法info,右边当编译器编译时执行类型擦除后Info接口中的类型参数T被替换成了Object类型,这时我们会发现Info接口中的抽象方法info的参数类型和返回值类型均为Object,对应的实现类中的方法info的参数类型和返回值类型均为Integer,我们都知道重写必须满足参数列表相同,但是此时不满足,所以就有了桥接方法的出现,通过桥接方法保持接口和类的实现关系

在理解完上图中的代码逻辑后,相信大家能看懂下面这段代码的执行结果(先打印fun:Integer,后打印fun:Object)

import java.lang.reflect.Method;

public class Test05 {
    public static void main(String[] args) {
        Class ii = IImpl.class;
        Method[] methods = ii.getDeclaredMethods();
        for (Method method : methods) {
            // fun:Integer
            // fun:Object
            System.out.println(method.getName()+":"+method.getReturnType().getSimpleName());
        }
    }
}

interface I {
    T fun();
}

class IImpl implements I {
    @Override
    public Integer fun() {
        return null;
    }
}
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号