【问题标题】:Generics Java Wildcards and Subtyping泛型 Java 通配符和子类型
【发布时间】:2016-04-09 10:17:27
【问题描述】:

我正在阅读 Java atm 中的泛型,事情进展得有点慢,希望能有所帮助。我从 Oracles 自己的数据库中读取:

https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html

在底部我们可以看到List<Integer>List<? extends Number>的子类型

我也遇到了这个stackoverflow问题:

Java Generic type : difference between List <? extends Number> and List <T extends Number>

在一个答案中说:这是真的:

((List<Integer>)list).add((int) s);

我已经验证过了,没关系。但我完全不明白。

如果通配符是 Short 类并且我添加了一个大于 2^15-1(=32767) 的数字,它不应该报错吗?

我什至尝试过类似的方法,但效果很好:

import java.util.*;
class CastingWildcard{
    public static void main(String[] args){
        List<? extends Number> list = new ArrayList<Short>();
        int s=32770;
        ((List<Integer>)list).add((int) s);
        System.out.println(list.get(0));
    }
}

总结一下:为什么我可以将List&lt;? extends Number&gt;转换为List&lt;Integer&gt;,而通配符可以是Short,甚至是Byte,它也扩展了Number?

【问题讨论】:

    标签: java generics


    【解决方案1】:

    强制转换使编译器忽略了一个事实,即类型可能不可分配。

    在运行时类型参数并不重要,参见type erasure

    ArrayList 在内部将内容存储在 Object[] 数组中,这意味着如果您“滥用”强制转换,您可以向列表对象添加任何引用类型。

    但是,当您检索 Object 时,您可能会遇到异常,因为 get 语句中隐藏了一个演员表。

    例子:

    List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
    List<String> list2 = (List) list;
    list2.add("Hello World");
    
    Integer i = list.get(0); // works
    String s = list2.get(3); // works
    s = list2.get(1); // ClassCastException
    i = list.get(3); // ClassCastException
    

    【讨论】:

    • 感谢您的回答。我稍后再看。
    • 在没有类型的情况下强制转换为 (List) 是什么意思?是否等于第二行的List&lt;String&gt; list2 = (List&lt;String&gt;)(Object)list?参考:stackoverflow.com/questions/1917844/…
    【解决方案2】:

    您可以将对象强制转换为您想要的任何东西,但它可能会在运行时失败。但是,由于在运行时不存在泛型信息,因此您的代码基本上变成了((List)list).add(s);。此时list 将采用any 对象,而不仅仅是Number。泛型可以帮助您在编译时避免强制转换并保持类型安全,但在运行时它们不再重要了。

    【讨论】:

    • 感谢您的回答。我稍后再看。
    猜你喜欢
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多