简体   繁体   English

为什么可以从Java中的参数化列表中找回“错误类型”的对象?

[英]Why is it possible to get back an object of “incorrect-type” from the parametrized List in Java?

Here's a code snippet: 这是一段代码片段:

import java.util.*;
class Test
{
    public static void main(String[] args)
    {
        List<Integer> list = new ArrayList<>();
        addToList(list);
        Integer i = list.get(0); //#1 fails at run-time
        String s = list.get(0); //#2 fails at compile-time
        list.get(0); //#3 works fine
        System.out.println(list.get(0)); //#4 works fine, prints "string"
    }
    static void addToList(List list){
        list.add("string");
    }
}

I understand why is it possible to insert an object of String class in parametrized List. 我理解为什么可以在参数化列表中插入String类的对象。

It seems like I understand why code marked with #1 and #2 fails. 似乎我理解为什么标有#1#2代码失败了。

But why do #3 and #4 work? 但为什么#3#4有效呢? As far as I understand, the compiler adds appropriate casts after type-erasure, so when I call list.get(0) , this method should return an Object previously casted to Integer. 据我所知,编译器在类型擦除后添加了适当的强制类型,因此当我调用list.get(0) ,此方法应该返回一个先前已转换为Integer的Object。 So why there is no ClassCastException occures at #3 and #4 at run-time? 那么为什么在运行时没有ClassCastException出现在#3和#4?

The #3 works because the object returned by get(int) is ignored. #3有效,因为忽略了get(int)返回的对象。 Whatever is stored at position 0 is returned, but since there is no cast, no error happens. 返回存储在位置0内容,但由于没有强制转换,因此不会发生错误。

The #4 works fine for the same reason: the object produced by get(0) is treated like java.lang.Object subclass in println , because toString is called. 由于同样的原因,#4工作正常: get(0)生成的对象被视为println java.lang.Object子类,因为调用了toString Since toString() is available for all Java objects, the call completes without an error. 由于toString()可用于所有Java对象,因此调用完成时没有错误。

First the reason why you can add a string to a List<Integer> . 首先,您可以将字符串添加到List<Integer> In the method 在方法中

static void addToList(List list){

you use a raw type . 你使用原始类型 Raw types exist purely for compatibility with older Java versions and should not be used in new code. 原始类型纯粹是为了与较旧的Java版本兼容而存在,不应在新代码中使用。 Within the addToList method the Java compiler does not know that list should only contain integers, and therefore it doesn't complain when a String is added to it. addToList方法中,Java编译器不知道该list应该只包含整数,因此在向其添加String时它不会抱怨。

As for the different behavior of you two statements. 至于你两个陈述的不同行为。 Integer i = list.get(0) does not fail at compile time, because Java thinks that list only contains Integer s. Integer i = list.get(0)在编译时不会失败,因为Java认为该list只包含Integer Only at runtime it turns out that the first element of list is not an Integer, and therefore you get a ClassCastException . 只有在运行时才会发现list的第一个元素不是Integer,因此你得到一个ClassCastException

String s = list.get(0) fails at compile time because the Java compiler assumes that list only contains Integers, and so it assumes you try to assign an Integer to a String reference. String s = list.get(0)在编译时失败,因为Java编译器假定list只包含整数,因此它假定您尝试将一个Integer分配给String引用。

Just list.get(0) does not store the result of the method call. 只是list.get(0)不存储方法调用的结果。 So neither at compile time nor at run time there is any reason for a failure. 因此,无论是在编译时还是在运行时都没有任何失败的原因。

Finally, System.out.println(list.get(0)) work because System.out is a PrintStream and has a println(Object) method, which can be called with an Integer argument. 最后, System.out.println(list.get(0))工作,因为System.out是一个PrintStream并且有一个println(Object)方法,可以使用Integer参数调用该方法。

If you look at ArrayList#get method. 如果你看一下ArrayList#get方法。 It is this: 就是这个:

public E get(int index) {
   //body
}

But at runtime it is actually: 但在运行时它实际上是:

public Object get(int index) {
       //body
}

So when you do Integer i = list.get(0); 所以当你做Integer i = list.get(0); The compiler converts it to: 编译器将其转换为:

Integer i = (Integer)list.get(0);

Now at runtime, list.get(0) returns an Object type (which is actually String ). 现在,在运行时, list.get(0)返回一个Object类型(实际上是String )。 It now tries converting String => Integer and it fails. 它现在尝试转换String => Integer并且它失败了。

3 3

Because it is just: 因为它只是:

list.get(0)

The compiler does add typecasting to anything. 编译器确实为任何事物添加了类型转换。 So it is just, list.get(0) . 所以它只是, list.get(0)

4 4

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

list.get(0) returns an Object type. list.get(0)返回一个Object类型。 So public void println(Object x) method of the PrintStream gets called. 因此调用PrintStream的public void println(Object x)方法。

Remember println(Object x) gets called and not println(String x) . 记住println(Object x)被调用而不是println(String x)

4: The overload System.out.println(Object) is being called, since Integer <=_T Object (read: Integer is-a Object). 4:正在调用重载System.out.println(Object),因为Integer <= _ T Object(读取:Integer是一个Object)。 Note that list.get(int) returns an Object in run-time since the type parameter gets erased. 请注意,list.get(int)在运行时返回一个Object,因为类型参数被擦除。 Now read 现在看了

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

that tells you "Insert type casts if necessary to preserve type safety.", since a type cast is not necessary from Object to Object the ClassCastException cannot result. 它告诉你“如果需要,插入类型转换以保持类型安全。”,因为从Object到Object不需要类型转换,所以不能产生ClassCastException。

For the same reason there is no type cast at 3, however side effects of the method call could happen of which List.get has none. 出于同样的原因,在3处没有类型转换,但是方法调用的副作用可能发生在哪个List.get没有。

The casts are applied to the return type of get , not to the add that's introducing the pollution. 演员阵容适用于get的返回类型,而不是引入污染的add Otherwise, you'd be getting either a compile-time error or an exception at that point, since you can't cast a String to an Integer . 否则,您将在此时获得编译时错误或异常,因为您无法将String转换为Integer

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从对象列表java中获取泛型类型 - get generic type from object list java 如何从参数化列表中获取Class对象以输入新对象声明? - How to get Class object from parametrized List for input to new object declaration? 如何从参数化List <T>创建Generic Type T的新对象 - How to create new object of Generic Type T from a parametrized List<T> 从对象列表Java 8获取具有转换类型的属性的列表 - Get a list of attributes wtih converted type from object list java 8 如何从Java方法获取返回的Objects对象类型列表? - How to get a returned List of Objects object type from a Java method? 为什么来自 MethodHandle 的 WrongMethodTypeException? 我的 object 类型不正确吗? - Why a WrongMethodTypeException from MethodHandle? Is my object type incorrect? Java Rest-使用GET方法发送参数化列表 - Java Rest - send parametrized List using GET method 从字段元素 - 注释处理器获取包名称和参数化类型 - Get package name and parametrized type from a field element - Annotation Processor 与父级一起使用的getActualTypeArguments从子级获取其参数化类型 - getActualTypeArguments with parent which get its parametrized type from the child Java-从列表中获取对象? - Java - Get an object from a list?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM