我使用以下代码(我使用的是JDK7)在编译时错误方面遇到了奇怪的行为:
public class classA { public void foo( List<Object> o ){} }
public class classB<T>{ public void bar( List<Object> o ){} }
我们考虑以下测试对象
List<String> o = new ArrayList<String>();
通过将 o 作为参数传递给类 classA 的方法 foo ,无法将java编译到目前为止我可以想象,不应该有。
现在说我们在classB的主要方法中并尝试只调用 bar 而不实例化classB的实例来调用它。我可能希望得到一个非静态方法不能从静态上下文编译错误调用,就像我试图在classA中拉它一样,但我得到转换调用错误。这是有道理的 - 类型不排队。
然而如果我从非静态上下文中尝试调用bar,就像在
中一样ClassB b = new classB();
b.bar( o );
Java似乎原谅我没有排列类型并运行代码没问题。我还没有做任何事情来解决typcasting的问题,那么为什么Java让这个代码执行,而不是classA呢?
编辑:回答一些问题。 classA仅供参考 - 它不应该编译,我不指望它,所以我不能提供编译它的代码。可以通过以下方式给出编译和执行的classB代码:
public class classB<T> {
public void bar( List<Object> o ){}
public static void main( String[] args ){
classB b = new classB();
List<String> o = new ArrayList<String>();
b.bar( o );
}
}
此代码编译并执行。完全相同的代码没有类声明行中的泛型声明不起作用。我理解有人提到的类型擦除,但它是如何帮助的,因为T不是方法栏或主代码中的引用
此外,有很多方法可以使这些代码更好。我真的只是在寻找对其行为的解释
答案 0 :(得分:4)
将类定义为
时class ClassB<T>
但将其实例化为
new ClassB().bar(new ArrayList<String>());
你实际上使用的是原始类型(没有泛型)版本。如果您发现有关类型安全的警告;方法签名为bar(List)
而不是bar(List<Object>)
:
类型安全:方法 bar(List)属于原始类型ClassB。应该参数化对泛型类型ClassB的引用。
如果您将参数化类型T
传递给String
new ClassB<String>().bar(new ArrayList<String>());
它不会与错误一起编译(再次注意方法签名)
The method **bar(List<Object>)** in the type ClassB<String> is not applicable for the arguments (ArrayList<String>)
答案 1 :(得分:4)
这是对泛型实施方式的限制。
他们选择加入。
classB b = new classB();
在这里,你选择退出泛型,你会收到警告。
Note: classB.java uses unchecked or unsafe operations.
当您选择退出泛型类型检查时,对于整个类,即使对于不使用绑定类型T
的方法,也不会获得任何类型检查。
正如@vandale指出的那样,关闭泛型,你甚至可以用
编译代码 public void bar( List<Float> o );
如果你做了
classB<Object> b = new classB<Object>();
它将不再编译。
答案 2 :(得分:0)
请尝试使用此代码:
public void method(List<? extends Object> o) { /* body */ }
这样它就会接受任何通用类型参数是Object的后代的列表,就像你想要的那样。 :)
答案 3 :(得分:0)
Java仍会产生“未经检查”的警告,但由于erasure而能够编译;即,类型List&lt; T&gt;和列表&lt; E&gt;在Java虚拟机中使用相同的非泛型底层类型。您可以将泛型视为仅用于在调用站点插入强制转换的语法糖并进行一些额外的检查,但在编译器发出的字节码中,就好像T和E被Object替换为无处不在,因此编译器能够将此视为警告而不是错误。