问题描述
我对以下代码有以下问题:
public class GenericBridgeMethods< T> {
public static void main(String [] args){
List obj = new ArrayList< Integer>();
列表<?> l1 =(List<> obj; //第1条
GenericBridgeMethods<?> g1 =(GenericBridgeMethods<>)obj; //条款2
}
}
a。第1条当然不会给予未经检查的投射警告
b。条款2也没有给出未经检查的转换警告我注意到从原始类型(obj)转换为任何可重用类型(如GenericBridgeMethods或GenericBridgeMethods )不会给出一个未经检查的施放警告。如果你运行这段代码,第2节会出现运行时错误。
编译器不应该在第2节给出警告
编辑1:
ArrayList a1 = new ArrayList< Integer>(); //第3条
数字n1 =(数字)a1; //子句4错误
比较c1 =(可比较)a1; //子句5
List l1 = new ArrayList< Integer>(); //第6条
数字n2 =(数字)l1; //第7条
比较c2 =(可比较)l1; //第8节
任何人都可以解释为什么只有第4节有错误吗?那么,首先在 GenericBridgeMethods 中定义它, T 不是可确定的类型。 Reifiable意味着该类型将被编码到类中并在运行时可用。这不是真的 T 。
第2条不给出运行时警告,因为它 / em> checked:将有一个运行时检查 obj 可以类型分配给 GenericBridgeMethods 类型。由于您选择了通配符作为类型参数,因此不需要检查 T 。
如果另一方面你做了这样的事情:
GenericBridgeMethods< String> g1 =(GenericBridgeMethods< String>)obj;
会给你一个未经检查的赋值警告,因为<$在运行时无法检查 obj 是 GenericBridgeMethods 字符串 s。但是,如果您这样做了,则会出现相同的警告:
List< String l1 =(List< String>)obj;
编辑
如果您感到困惑至于为什么编译器允许您尝试将 List 转换为 GenericBridgeMethods ,答案是因为编译器可以不知道 GenericBridgeMethods 及其子类的整个层次结构。可能有 GenericBridgeMethods 的子类实现 List ,在这种情况下,cast 可能如果您制作 GenericBridgeMethods a,您将 最后一堂课(并因此阻止了它的子类)。在这种情况下,你会得到不可转换的类型错误。
为了向您展示您的问题与可定义类型和泛型没有多大关系,请看一下:
public static void main(String [] args){
List obj = new ArrayList< Integer>
//这是允许的(没有警告),即使它在运行时会失败
CharSequence sequence =(CharSequence)obj;
}
您可以显式地投射 obj 到 CharSequence ,即使你知道它在运行时会失败。原因是因为所有编译器都知道 obj 是 List 类型。由于 List 是一个接口,因此可能有一个 CharSequence 的实现,它也是一个 List
每个显式演员都有一定程度的可能会失败在运行时。否则,这将是多余的转换,编译器应该允许您省略显式转换。编辑 - 关于您的编辑#1
ArrayList a1 = new ArrayList< Integer>(); //第3条
数字n1 =(数字)a1; //子句4错误
比较c1 =(可比较)a1; //子句5
List l1 = new ArrayList< Integer>(); //第6条
数字n2 =(数字)l1; //第7条
比较c2 =(可比较)l1; //第8节
你想知道为什么只有子句4不能编译。我想我已经在上面和评论中解释了这一点,但我会逐步详细地介绍这个具体示例。
ArrayList a1 = new ArrayList< Integer>(); //第3条
数字n1 =(数字)a1; //子句4错误
正在铸造 a1 到 Number 不起作用,因为 Number 和 ArrayList 都是类,而不是接口。因为Java不允许从多个类继承,所以对象是 Number 和 ArrayList code>, Number 必须是 ArrayList 的子类,反之亦然。这已知在编译时不是真的。
ArrayList a1 = new ArrayList< Integer>(); //第3节
可比较的c1 =(可比较的)a1; //第5节
由于可比是接口, ArrayList 的子类可能是 Comparable 。
List l1 = new ArrayList< Integer>(); //第6条
数字n2 =(数字)l1; //第7条
自 List 是接口 Number 的子类可以实现 List 。编译器不知道何时检查 l1 持有 ArrayList 。
I have the following question regarding the code below:
public class GenericBridgeMethods <T> { public static void main(String[] args) { List obj = new ArrayList<Integer>(); List <?> l1 = (List<?>) obj; // clause 1 GenericBridgeMethods <?> g1 = (GenericBridgeMethods<?>) obj; // clause 2 } }
a. Clause 1 of course won't give an unchecked cast warning
b. Clause 2 also did not give an unchecked cast warning
I noticed that a cast from a raw type (obj) to a ANY reifiable type (like GenericBridgeMethods or GenericBridgeMethods <?>) will not give a unchecked cast warning. If you run this code, a runtime error will occur at clause 2.
Shouldn't the compiler give a warning at clause 2
EDIT 1:
ArrayList a1 = new ArrayList<Integer>(); // clause 3 Number n1 = (Number)a1; // clause 4 ERROR Comparable c1 = (Comparable)a1; // clause 5 List l1 = new ArrayList<Integer>(); // clause 6 Number n2 = (Number)l1; // clause 7 Comparable c2 = (Comparable)l1; // clause 8
Can anyone explain why only clause 4 has error?
Well, first off in GenericBridgeMethods as you have defined it, T is not a reifiable type. Reifiable means that the type will be encoded into the class and will be available at runtime. That is not true of T.
Clause 2 does not give a runtime warning because it is checked: There will be a runtime check that obj is type-assignable to the GenericBridgeMethods type. Since you've opted for a wildcard as the type parameter, nothing about T needs to be checked.
If on the other hand you did something like this:
GenericBridgeMethods<String> g1 = (GenericBridgeMethods<String>) obj;
that would give you an unchecked assignment warning because the fact that obj is a GenericBridgeMethods of Strings cannot be checked at runtime. However, the same warning would appear if you had done this:
List<String l1 = (List<String>) obj;
Edit
If you're confused as to why the compiler allows you to try to cast a List to a GenericBridgeMethods, the answer is because the compiler can't know the entire hierarchy of GenericBridgeMethods and its subclasses. There could be a subclass of GenericBridgeMethods that implements List, in which case the cast might be legitimate.
You will however get a compile error if you made GenericBridgeMethods a final class (and thus prevented it from having subclasses). In this case, you will get an inconvertable types error.
Just to show you your question has little to do with reifiable types and generics, take a look at this:
public static void main(String[] args) { List obj = new ArrayList<Integer>(); //this is allowed (no warning), even though it will fail at runtime CharSequence sequence = (CharSequence) obj; }
You can explicitly cast obj to a CharSequence even though you know that it will fail at runtime. The reason is because all the compiler knows is that obj is a type of List. Since List is an interface, there could be an implementation of CharSequence that is also a List, and so the cast must be permitted.
Every explicit cast carries a degree of possibility that it could fail at runtime. Otherwise, it would be a redundant cast and the compiler should allow you to omit the explicit cast.
Edit - Regarding your "edit #1"
ArrayList a1 = new ArrayList<Integer>(); // clause 3 Number n1 = (Number)a1; // clause 4 ERROR Comparable c1 = (Comparable)a1; // clause 5 List l1 = new ArrayList<Integer>(); // clause 6 Number n2 = (Number)l1; // clause 7 Comparable c2 = (Comparable)l1; // clause 8
You are wondering why only "clause 4" does not compile. I think I explained this already above and in the comments, but I'll go thsough this specific example for you step-by-step.
ArrayList a1 = new ArrayList<Integer>(); // clause 3 Number n1 = (Number)a1; // clause 4 ERROR
Casting a1 to Number does not work because Number and ArrayList are both classes, not interfaces. Because Java does not allow inheritance from multiple classes, for an object to be an instance of both Number and ArrayList, Number would have to be a subclass of ArrayList or vice versa. This is known to not be true at compile time.
ArrayList a1 = new ArrayList<Integer>(); // clause 3 Comparable c1 = (Comparable)a1; // clause 5
Since Comparable is an interface, a subclass of ArrayList might be a Comparable.
List l1 = new ArrayList<Integer>(); // clause 6 Number n2 = (Number)l1; // clause 7
Since List is an interface a subclass of Number could implement List. The compiler does not know when checking the cast that l1 holds an ArrayList.
这篇关于Java泛型:将原始类型转换为任何可调整类型不会生成未经检查的转换警告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!