public class Main {
public static void main(String[] args) {
ArrayList<String> strList = new ArrayList<String>();
Type type = ((ParameterizedType)strList.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
System.out.println(type);
}
}
public class Main {
public static void main(String[] args) {
ArrayList<String> strList = new ArrayList<String>(){};
Type type = ((ParameterizedType)strList.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
System.out.println(type);
}
}

这两个例子唯一的区别是后者的new ArrayList<String>(){}初始化strList的时候带了{}执行了赋初值,虽然语法层面没有什么区别,但是在编译之后的结果却完全不一样。而且执行的结果也完全不一样,
前者执行结果:

E

后者执行结果:

class java.lang.String

前者的编译结果:

public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
12: invokevirtual #5 // Method java/lang/Class.getGenericSuperclass:()Ljava/lang/reflect/Type;
15: checkcast #6 // class java/lang/reflect/ParameterizedType
18: invokeinterface #7, 1 // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
23: iconst_0
24: aaload
25: astore_2
26: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
29: aload_2
30: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
33: return

这个逻辑很简单,就是简单的invokespecialArrayList<init>()方法。

后者的编译结果:

public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: new #2 // class Main$1
3: dup
4: invokespecial #3 // Method Main$1."<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #4 // Method java/lang/Object.getClass:()Ljava/lang/Class;
12: invokevirtual #5 // Method java/lang/Class.getGenericSuperclass:()Ljava/lang/reflect/Type;
15: checkcast #6 // class java/lang/reflect/ParameterizedType
18: invokeinterface #7, 1 // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
23: iconst_0
24: aaload
25: astore_2
26: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
29: aload_2
30: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
33: return

这里就奇怪了,加了{}之后竟然生成了内部类Main$1:

final class Main$1 extends java.util.ArrayList<java.lang.String>
...
{
Main$1();
descriptor: ()V
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/util/ArrayList."<init>":()V
4: return
LineNumberTable:
line 8: 0
}
Signature: #9 // Ljava/util/ArrayList<Ljava/lang/String;>;
...

java.util.ArrayList<java.lang.String>的子类,这也就解释了后者的执行结果为何可以解析到strList的泛型参数化类型是java.lang.String了,因为它的实际类型在JVM执行的时候清楚地被标记成了内部类Main$1这个java.util.ArrayList<java.lang.String>的子类。而前者的strList的泛型参数化类型已经被擦除掉了。

Java泛型和编译优化的一个例子的更多相关文章

  1. 转PostgreSQL 用游标优化的一个例子

    一位PG社区的朋友提到的一个应用场景,目前遇到性能问题. 数据结构大概是这样的,包含一个主键,一个数组,一个时间,其他字段. 请求分析: 有检索需求,比较频繁.查找数组中包含某些元素的记录,并按时间排 ...

  2. Java——泛型

    前言 一般的类和方法,使用的都是具体的类型:基本类型或者自定义的类.如果我们要编写出适用于多种类型的通用代码,那么肯定就不能使用具体的类型.前面我们介绍过多态,多态算是一种泛化机制,但是也会拘泥于继承 ...

  3. 深入理解java泛型

    一. 什么是泛型? 泛 型(Generic type 或者 generics)是对 简单的理解,就是对类型的参数化,比如我们定义一个类属性或者实例属性时,往往要指定具体的类型,如Integer.Per ...

  4. Java - 28 Java 泛型

    Java 泛型 如果我们只写一个排序方法,就能够对整型数组.字符串数组甚至支持排序的任何类型的数组进行排序,这该多好啊. Java泛型方法和泛型类支持程序员使用一个方法指定一组相关方法,或者使用一个类 ...

  5. 20180826(03)-Java泛型

    Java 泛型 如果我们只写一个排序方法,就能够对整形数组.字符串数组甚至支持排序的任何类型的数组进行排序,这该多好啊. Java泛型方法和泛型类支持程序员使用一个方法指定一组相关方法,或者使用一个类 ...

  6. Java泛型的一些限制

    本文主要參考<Java编程思想(第4版)>的Java泛型章节,仅当一个简单的读书笔记. 和C++泛型对照,Java泛型仅仅是一种编译期间的擦拭机制. 这是因为考虑到和曾经的兼容而考虑的一种 ...

  7. Java泛型读书笔记 (二)

    关于Java泛型擦除后,继承一个泛型类带来的问题 有如下泛型类Pair: public class Pair<T> { private T second; private T first; ...

  8. java泛型笔记一

    名词:泛型类 泛型方法 原始类型 子类型 版本 参数化类型 通配符类型 超类通配 子类通配 全通配 定义变量 创建对象 检查模板 类型实参 类型形参 补充 替代语法特征:尖括号括起来的类型参数表 // ...

  9. Java泛型反射机制(二)

    /** * @author Administrator * 好处:泛型:1安全 2减少代码重用率 */ package com.test; import java.lang.reflect.Metho ...

随机推荐

  1. shell重定向输出的应用

                         shell重定向输出的应用 案例2:重定向输出的应用 2.1问题 本例要求编写一个脚本/root/out.sh,功能特性如下: 执行此脚本显示I love s ...

  2. adb工作常用命令

    adb devices 查看手机名 adb shell链接手机 dumpsys window windows |grep -i current 打开软件,查看软件入口,和包名,白色为包名,红框为包入口 ...

  3. Scratch 怎么打开SB文件怎么打开

    扩展名是.sb( )的文件均可以用匹配版本的scratch或比匹配版本高的scratch打开,列表如下:类型 可打开.sb ···1.4(1.3).sb2 ···2.0.sb3··· 3.0或3.0b ...

  4. mpvue小程序开发

    查阅资料,看官方文档,知道mpvue是一个使用 Vue.js 开发小程序的前端框架(美团的开源项目).框架基于 Vue.js 核心,mpvue 修改了 Vue.js 的 runtime 和 compi ...

  5. MTK Android 读取SIM卡参数,获取sim卡运营商信息

    android 获取sim卡运营商信息(转)   TelephonyManager tm = (TelephonyManager)Context.getSystemService(Context.TE ...

  6. SQL表的简单操作

    创建数据库表,进行增删改查是我们操作数据库的最基础的操作,很简单,熟悉的请关闭,免得让费时间. 1.创建表: sql中创建数值类型字段要根据该字段值的增长情况选择类型: tinyint 占1个字节,长 ...

  7. day01-课后作业

    #1.写一个登陆的程序,最多登陆失败3次#2.输入账号 密码,如果登录成功,程序结束,提示 欢迎 xx 登录,今天的日期是 xx#3.登录失败,重新登陆#3.要判断输入是否为空,什么也不输入,输入空格 ...

  8. 【docker】为docker下的php容器安装php-redis扩展【编译安装】

    使用docker安装的PHPFPM容器没有Redis扩展,需要安装一下扩展. 首先进入docker的PHPFPM容器 $ docker exec -it myphpfpm /bin/bash 依次执行 ...

  9. 一个java 码手 的老牛 --- 涉及 一些不错的java 基础课程

    http://www.zuidaima.      com/user/1550463811307520/share/collect.htm

  10. python字节码,java字节码,十六进制相互转换

    下面是互相转换的代码: 有想要了解更多关于python知识的请在下方评论或私信小编