泛型 编译器给的‘蜜糖’那些事!

最近在论坛上看到一哥们,写了个反射的小测试程序 代码如下:

示例 代码1 运行正常 如下 :

List<Integer> list1 = new ArrayList<Integer>();
list1.getClass().getMethod("add", Object.class).invoke(list1, "abc");
System.out.println(list1.get(0));

示例 代码2 运行就异常了 如下:

ArrayList<String> list2 = new ArrayList<String>();
list2.getClass().getMethod("add", Object.class).invoke(list2, 12);
System.out.println(list2.get(0));


我一看,首先想到的是,反射加载Class 对象得到的add方法是经类型擦除的,肯定能使ArrayList<Integer>中add一个字符串,当然反射也能使ArrayList<String>中add一整数。

但是上面示例代码1 运行正常, 代码2 运行却异常了,为什么呢? 开始老想到的是 泛型的类型擦除。

后面想到Integer Num = 4; 能正常的执行,并生成了Num的对象,这个我知道,是编译器给的蜜糖 ,

Integer inter = 4 相当于 Integer inter = Integer.valueOf(4)。 也就是编译器在读取.java文件时,发现Integer inter =4,它会自动把4 替换成了Integer.valueOf(4)。

int num = inter时,编译器也帮忙补齐全代码成了 int num = inter.intValue(); 这样在运行时也就没有问题了。

那么这个泛型引用的 初衷不正也是要去掉繁琐的强转吗,所以会不是编译器搞的鬼呢。 经找相应的反编译工具,对.class文件进行反编译,发现了:

代码2中

System.out.println(list.get(0));

变成了

System.out.println((String)list.get(0));

而代码1中则不用变成,因为编译器看到代码1中的ArrayList是 Integer,用S.O.P调用时可以传入到Object参数类型的println方法中。

理解了这个,然后又找了相应的方法去测试

如:

将示例1代码改了 示例代码3:

List<Integer> list1 = new ArrayList<Integer>();
list1.getClass().getMethod("add", Object.class).invoke(list1, "abc");
System.out.println(list1.get(0).toString());

在示例代码3中 在list.get(0)后面接着调用了toString()方法时,就报错了。为什么呢?

一句话,编译器搞的鬼自作 聪明在 list.get(0)前加了强转成了Integer。

System.out.println(list1.get(0).toString())

被编译器弄成了:

System.out.println(
  ((Integer)list1.get(0)).toString()
);


结束语:

泛型,自动装箱,引用本身也是好的。但反射时,使用需要小心了。 编译器给的蜜糖要小心了。

----编后补充:

刚不小心研究了下 可变参数,特点比较简单了,如
1. 可变参数 类型后面必须要紧跟的三个小点. 。且三个小点,不可以放在变量名形参后面,只能放在变量名与类型之间,中间有无空格不重要。

但建议是类型后面紧跟三个小点。

2. 调用消费此方法时,也比较简单,可支持多个实参,可变的实参传下(即所谓的实参数量可变)

原理呢,为什么能够支持可变参数呢,Type... 到道是什么呢,传入的实参数是为什么可变呢。

想了好久没有解释,后面想想是不是又是编译器给的好处呢。 于是乎有了下面的测试。

avilabePareDemo("asdfa","badf","323"); //注意这是main方法中处的代码,这里为了简便,不贴main方法了。

public static void avilabePareDemo(String... args){
		for(int i=0;i<args.length;i++){
			System.out.println(args[i]);
		}
	}

经过反编译一直,居然被编译成了:

avilabePareDemo(new String[] { "asdfa", "badf", "323" });

public static void avilabePareDemo(String[] paramArrayOfString) {
    for (int i = 0; i < paramArrayOfString.length; ++i)
      System.out.println(paramArrayOfString[i]);
  }


从上面看出来:

1. 调用处编译器 自动加了个 new String[] {"asdfa", "badf", "323"} 的数组,传给可变方法,替换了前面的"asdfa", "badf", "323"三个参数

2. 可变方法的形参呢,被反编译成了String[] paramArrayOfString 替换了前面的可变String...



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值