前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java泛型擦除

Java泛型擦除

作者头像
shysh95
发布2021-03-16 11:18:19
7470
发布2021-03-16 11:18:19
举报
文章被收录于专栏:shysh95

在我们讲述Java编译原理(javac)时,其中涉及到了一个解语法糖。

语法糖只不过是一种程序的表达式,语法糖可以提高程序的可读性,语法糖经过编译后,将会恢复原来的样貌。

  • 泛型和类型擦除
  • foreach语法

1. 泛型和类型擦除

泛型的本质是参数化类型,这个参数类型可被用在接口、类、方法上,分别称为泛型接口、泛型类、泛型方法。

1.1 为什么要引入泛型

没有泛型的Java只能通过Object强制转换成具体的类型,这种写法极其不美观,而且需要程序员去保证这个强转操作的正确性,否则极有可能在虚拟机运行的时候抛出ClassCastException。

1.2 类型擦除

Java中的泛型是伪泛型,泛型只会在程序源码中存在,在编译后的class文件中,参数类型将会被抹除(类型擦除)。

代码语言:javascript
复制
public class ClassTest {

    public static void main(String[] args) {
        List<String> result = new ArrayList<>();
        result.add("test");
        System.out.println(result.get(0));
    }
}

上述Java代码经编译过后,会生成class文件,我们再对class文件反编译,得到的程序代码如下:

代码语言:javascript
复制
public class ClassTest {
    public ClassTest() {
    }

    public static void main(String[] var0) {
        ArrayList var1 = new ArrayList();
        var1.add("test");
        System.out.println((String)var1.get(0));
    }
}

这里我们可以看到,泛型中的String已经被完全擦除,并且当我们从list中取回数据时自动强转成了String。Java编译器会自动将泛型擦除,将强转添加。

代码语言:javascript
复制
public class ClassTest {

    public static void test(List<String> args) {
    }

    public static void test(List<Integer> args) {
    }
}

上述代码编译不会通过,因为List和List最终都会变为List。

1.3 Signature

Signature是属性表中的一项属性,可作用于类、方法表、以及字段表。

由于Java泛型的引入,各种场景下的方法调用都可能产生影响,如在泛型类中如何获取参数化类型。

代码语言:javascript
复制
public class ClassTest {

    public List<Double> test(List<String> args, List<Integer> args1) {
        return null;
    }
}

上述源码编译成class文件以后,我们在使用java -p指令来看一下字节码文件,如下图:

Signature一个重要的作用就是保存了参数化类型,这样以后通过这个属性我们就可以获取到参数化类型。

2. foreach语法

代码语言:javascript
复制
public class ClassTest {

    public static void main(String[] args) {
        List<String> result = new ArrayList<>();
        result.add("test");
        for (String r : result) {
            System.out.println(r);
        }
    }
}

上述foreach语法在经过编译后,变成了使用Iterator进行遍历。

代码语言:javascript
复制
public class ClassTest {
    public ClassTest() {
    }

    public static void main(String[] var0) {
        ArrayList var1 = new ArrayList();
        var1.add("test");
        Iterator var2 = var1.iterator();

        while(var2.hasNext()) {
            String var3 = (String)var2.next();
            System.out.println(var3);
        }

    }
}

通过上述我们也可以看出,如果想要使用foreach语法,该类必须要实现Iterable接口。

Java中除了上述两种语法糖,还有诸如内部类、自动装箱、自动拆箱、try语句定义和关闭资源等,分析方法均如上述,感兴趣的读者可以自行分析。

本期的Java语法糖介绍到这,我们下期再见!!!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档