前言
// 年轻时候,到了冬天,家人让你穿秋裤,你不仅不穿秋裤,还露着脚脖子,如果有人劝你,你会嫌他唠叨。而等你岁数大一点,天气一冷,身体受不了,就自觉把秋裤穿上了。
呵呵 昨天的时候发现了这样的一个问题 泛型强转类型之后取数据的一个疑问,问题不好描述请看代码和截图吧。, 然后记录了一个 todo, 来看了一下
还是挺有意思的, 作者 本身也做了一定的思考
本以为 这个没有多少可以记录的内容, 没有想到 还是有一些细节的地方
以下内容基于 jdk8
测试用例
测试用例的主要内容来自于文章 泛型强转类型之后取数据的一个疑问,问题不好描述请看代码和截图吧。 | HeapDump性能社区
主要的问题在于 上面的 listTest.get 没有做 check cast, 下面的 listStr 做了 check cast
按正常的逻辑来考虑, listTest.get 应该是也需要做 check cast
/**
* Test03GenericTypeCast
*
* @author Jerry.X.He
* @version 1.0
* @date 2022-02-08 09:27
*/
public class Test03GenericTypeCast {
// Test03GenericTypeCast
public static void main(String[] args) throws Exception {
ArrayList<String> listStr = new ArrayList<String>();
listStr.add("只能添加String类型");
Class c2 = listStr.getClass();
Method m = c2.getMethod("add", Object.class);
m.invoke(listStr, 20);//注意listStr只能添加String类型,我们现在可以通过反射的手段绕过编译器给他加一个整形进去
System.out.println("注意整形已经添加进去了,List的元素个数为:-> " + listStr.size());
System.out.println();
Object obj = listStr;
ArrayList<Boolean> listTest = (ArrayList<Boolean>) obj;
// ArrayList<Integer> listTest = (ArrayList<Integer>) obj;
// ArrayList<StringBuffer> listTest = (ArrayList<StringBuffer>) obj;
System.out.println("看看listTest的Class类型到底是什么类型:-> " + listTest.getClass());
System.out.println("我想得到一个Boolean类型,但是得到确实String类型,这是为什么,为什么这里没报错?:-> " + listTest.get(0));
System.out.println("我想得到一个Boolean类型,但是得到确实String类型,这是为什么,为什么这里没报错?:-> " + listTest.get(1));
System.out.println("上面没报错就很奇怪,一定要搞明白");
System.out.println();
System.out.println("下面的会报错我能理解,上面的没报错我就不能理解?");
System.out.println("listStr的toString方法,注意整形也可以输出出来: " + listStr.toString());
System.out.println("看看listStr的Class类型到底是什么类型:-> " + listStr.getClass());
//Integer in = list2.get(1);编译直接就报错了
System.out.println(listStr.get(1));//这里会什么又会报错了,因为lis2认为20是String类型的,结果就报错了,java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
}
}
javac 层面的分析
最直接的来看一下 javac 到底做了什么 ?, 这是第一个层次
先看一下 "listTest.get(0)" 这里面 pt 表示的是表达式期望的类型, mt.returnType 是表达式泛型擦除之后的类型, 这里两个类型是兼容的, 因此
因此没有生成这个 check cast
再来一下 "listStr.get(0)", 期望的类型是 String, 然后 泛型类型擦除之后的类型是 Object, 不兼容于 String, 因此 增加了一个 check cast
类型不兼容, javac 增加了一个 check cast
listTest.get(0) 和 listStr.get(0) 的类型来自于哪里?
这个问题是 本问题的关键
listTest.get(0) 的类型来自于这里的 + operator 的第二个参数, 类型是 Object
然后这个约束是来自于 字符串连接符 "+"
具体代码层面的 resolve 是在这里
具体的 字符串连接符 "+" 的一些类型约束
我们这里表达式 "我想得到一个Boolean类型,但是得到确实String类型,这是为什么,为什么这里没报错?:-> " + listTest.get(0)
左边的操作数是一个 string, 右边的操作数匹配不上 原始类型 或者 String, 因此匹配的是 String + Object
listStr.get(0) 的类型, 取决于 System.out.println, 选择的是 类型 String
jls 中的 String Concatenation Operator +
完
参考
泛型强转类型之后取数据的一个疑问,问题不好描述请看代码和截图吧。 | HeapDump性能社区
03 为Map.put的增加的checkcast & 增加了一段业务无关的 instance.getClass() 的调用_970655147的专栏