我理解泛型和强制转换,但我不理解什么是泛型转换。我原以为只能通过继承树向上或向下转换到特定类型,但这证明了我的错误:
ArrayList<?> cislo = (ArrayList<? extends Number>) new ArrayList<Integer>();
这可能不是最好的例子,但希望你能理解我的意思。它是如何工作的?被分配到哪种类型?
演员阵容不必要。
分配任务
ArrayList<?> list = new ArrayList<Integer>();
ArrayList<? extends Number> list2 = new ArrayList<Integer>();
不需要任何显式转换。
通配符类型比具体类型更“一般”/“不太具体”,上界通配符类型(如? extends Number
)比无界通配符类型(?
)更具体。
有关通配符类型之间关系的更多信息,请参阅Oracle Wildcards and Subtyping教程。
规定这一点的JLS相关部分是4.10.2。类和接口类型之间的子类型关系。
给定通用类型声明C(n>0),参数化类型C的直接超类型,其中Ti(1≤i≤n)是一种类型,都是以下所有类型:[...]
这是指4.5.1. Parameterized Types的类型参数。? extends T <= ? extends S,如果T <: S
? extends T <= ?
因此,按照这个定义,ArrayList<? extends Number>
是ArrayList<Integer>
的超类型,ArrayList<?>
是任何ArrayList<>
(原始类型除外)的超类型。
对于超类型的变量赋值不需要进行强制类型转换。
如果您想分配不同类型的内容,则需要进行转换:
Object list = new ArrayList<Integer>();
//...somewhere else - the compiler does not know that list is always an ArrayList, but we tell it that we know what we are doing
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but works
这样转换后,您可以从列表中获取元素并将其视为数字
。如果您将不是List<? extends Number>
子类型的内容分配给list
引用,则转换会在运行时失败。
Object list = new HashSet<Integer>();
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning
在运行时抛出异常
java.lang.ClassCastException: java.util.HashSet无法转换为java.util.List
List<String> stringList = new ArrayList<String>();
stringList.add("hi");
Object list = stringList;
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but (sadly) works
Number n = numbers.get(0); //fails: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
ArrayList<Integer>
处理为ArrayList<? extends Number>
并保持安静(除了警告之外,基本上与将Number
变量强制转换为Integer
相同 - 您告诉编译器您知道自己在做什么)。对于ArrayList<?>
的赋值在任何情况下都可以工作。 - Thomas@ReesmoConfiguration(storage = RestApiStorage.class)
,在抽象超类Storage中,我找到了工厂方法newInstance(Object configuration){ Class extends Storage> clazz = null; if (Bool.FALSE.equals(Property.ENABLED.get(configuration))) { clazz = DummyStorage.class; } else { clazz = (Class extends Storage>) Property.STORAGE.get(configuration); } if (clazz.isAssignableFrom(DummyStorage.class)) { return new DummyStorage(); }}
- Petr BenešClass<? extends Storage> clazz = (Class<? extends Storage>) Property.STORAGE.get(configuration);
- 如果get
返回的对象是Storage
子类型的类对象,则此代码将起作用。如果get
的返回类型是其超类型(例如Object
或某个接口),则需要进行强制转换。 - Hulk