提问人:Matthew S. 提问时间:3/4/2021 最后编辑:Matthew S. 更新时间:3/5/2021 访问量:116
类型参数是否与参数一起传递给方法?
Are type arguments passed along with an argument to a method?
问:
从我自己的实验中,我得出结论,当作为参数传递给方法时,对象或对象引用的任何类型参数都会被剥离。如果使用类型参数参数化方法的参数,则会弹出类型参数的问题:
<T> void method (ArrayList<T> list) {
list.add( (T) new Integer(4));
sysout (list.get(0));
}
然后,如果我们将两个参数化的 ArrayList 中的每一个都传递给此方法的调用:
method(new ArrayList<Integer>());
method(new ArrayList<String>());
我们将看到两者都不会产生错误,并且都打印 4。我假设编译器保留了 as 的擦除。这个实验难道不能证明类型参数没有传递给方法吗?T
Object
答:
an 的情况实际上与普通的情况相同。在这两种情况下,在编译时用于静态类型检查。但是,在运行时,会被擦除。ArrayList<T>
T
T
T
查看您发布的代码,编译后的方法是等效的:
void method (ArrayList<Object> list) {
list.add( (Object) new Integer(4));
sysout (list.get(0));
}
调用实际上是:
method(new ArrayList<Object>());
method(new ArrayList<Object>());
因此,从运行时的角度来看,您存储在 中,这很好。Object
ArrayList<Object>
现在,如果没记错的话,您应该会收到有关表达式 的未选中强制转换的警告。这是一个很好的警告,需要注意!如果目标类型与实际类型不兼容,则强制转换通常会引发异常。但是,在这种情况下,在运行时不存在,因此无法动态检查 - 强制转换是无操作的。但是,如果我们修改示例以返回强制转换的值,您可能会在运行时开始看到问题:(T) new Integer(4)
T
<T> T method (ArrayList<T> list) {
T value = (T) new Integer(4);
list.add(value);
return value;
}
然后
String result = method(new ArrayList<String>());
即使强制转换成功(这只是一个无操作),当返回值被赋值时,也会引发异常,因为该值是 an 而不是 .result
Integer
String
评论
Object
new ArrayList<Object>
"
T
T
ArrayList<String> list = new ArrayList();
list = new ArrayList<String>();
list = new ArrayList<Integer>();
new
This is just a simple case where the compiler isn't enabled to force you to use within certain bounds. It's a bit as if your method doesn't care about as a type, as you noticed.T
method()
T
The code is compiling, but with a warning. Your unchecked cast to is not always without consequences:T
ArrayList<String> strings = new ArrayList<>();
method(strings);
System.out.println(strings.get(0));
And:
Exception in thread "main" java.lang.ClassCastException:
java.lang.Integer cannot be cast to java.lang.String
This exception is raised by , because this call to is linked to the overload taking a String, and the cast doesn't pass.System.out.println(strings.get(3));
println
That means that although doesn't check the cast to (at compile time or at runtime), the caller does. In my method, is inferred as and the runtime is able to perform the relevant type checks.method()
T
main()
T
String
I assume that the compiler retains the erasure of as .
T
Object
Roughly speaking, yes. But the compiler would be able to enforce more type safety in other cases, where is bounded. The following won't even compile:T
static <T extends String> void method(ArrayList<T> list) {
list.add((T) new Integer(4));
System.out.println(list.get(0));
}
So, "Does this experiment not prove that type arguments aren't passed to a method?" No. This is just one scenario of many.
评论
strings
Number
Integer
Double
Double
Integer
T
Object
T
评论
T
是无界的,所以你真正拥有的是一个.这就是编译代码的原因。ArrayList<Object>
List
List<T>
List