Java中重写泛型方法的正确方法
考虑以下代码:Java中重写泛型方法的正确方法,java,generics,type-erasure,raw-types,Java,Generics,Type Erasure,Raw Types,考虑以下代码: 导入java.util.array; 导入java.util.List; 类人{} 类OtherPerson{} 类SomeDummyClass{} 接口A{ List foo(); } 类B实现了一个{ @凌驾 公开名单foo(){ 返回Arrays.asList(Integer.valueOf(3)、newperson()、newotherperson()); } } 公共班机{ 公共静态void main(字符串[]args){ A=新的B(); 列出someDummyCl
导入java.util.array;
导入java.util.List;
类人{}
类OtherPerson{}
类SomeDummyClass{}
接口A{
List foo();
}
类B实现了一个{
@凌驾
公开名单foo(){
返回Arrays.asList(Integer.valueOf(3)、newperson()、newotherperson());
}
}
公共班机{
公共静态void main(字符串[]args){
A=新的B();
列出someDummyClasses=a.foo();
System.out.println(someDummyClasses.get(0));//打印3
}
}
我不明白为什么我们可以重写foo()
方法而不产生任何编译时错误。当我编写List someDummyClasses=a.foo()时,这一点就变得不那么直观了代码>这是完全有效的(没有编译时错误)
这种情况的一个实时示例是使用mybatis-3
A
模仿
B
mimics(这个类不是包私有的-我想它应该是这样的)
foo()
模仿
问题
- 我明白为什么这句话:
List someDummyClasses=a.foo()代码>未给出任何编译时错误。但在运行时,我认为它应该给出一个ClassCastException
。这里到底发生了什么
- 当我执行
System.out.println(someDummyClasses.get(0))代码>我得到一个ClassCastException
。为什么会这样
- 有没有更好的方法来重新编写这些代码,使代码变得不那么脆弱
1)A#foo的签名是返回一个列表
,该列表将返回一个在关联时被捕获为E的类型列表,列表=新的A().foo()
(如果A是一个具体的类)编译,因为它捕获了该类型,而列表=新的B().foo()
返回一个列表
,并且无法分配
第二)由于给列表分配了整数和字符串,因此得到了ClassCastException
3)您的界面可能有类似的listfoo()代码>将B类上的声明转换为无效等,由于您事先知道E
但在运行时,我认为它应该给出一个ClassCastException。这里到底发生了什么
请记住,Java中的泛型纯粹是编译时的东西。编译代码时,编译器将删除所有泛型参数,并在必要时添加强制转换。运行时的代码如下所示:
interface A {
List foo();
}
class B implements A {
@Override
public List foo() {
return Arrays.asList(Integer.valueOf(3), new Person(), new OtherPerson());
}
}
// ...
List someDummyClasses = a.foo();
System.out.println(someDummyClasses.get(0));
看!这里没什么问题。没有强制转换,更不用说ClassCastException
s了
如果您这样做,将出现ClassCastException
:
SomeDummyClass obj = someDummyClasses.get(0);
因为上面的代码在运行时会变成这样:
SomeDummyClass obj = (SomeDummyClass)someDummyClasses.get(0);
当我执行System.out.println(someDummyClasses.get(0))时;我得到一个ClassCastException
。为什么会这样
有没有更好的方法来重新编写这些代码,使代码变得不那么脆弱
(请注意,我对mybatis了解不多)
我认为您应该在这里做的是使成为一个
通用接口:
interface A<T> {
List<T> foo();
}
接口A{
List foo();
}
并使B实现A
。这样,至少它更安全
我不明白为什么我们可以用任何编译重写foo()方法
时间错了
是,但您有一个编译警告,因为重写方法List
中的返回类型比接口方法中的List
更具体:
未经检查的覆盖:返回类型需要未经检查的转换。建立
java.util.List
,必需java.util.List
不处理此类警告可能会导致泛型的使用不一致。这里有一个很好的例子
关于:
当我写这篇文章时,这一点就变得不那么直观了
列出someDummyClasses=a.foo();这是完美的
有效(无编译时错误)
为什么会出现编译错误
这里您将a
声明为a
:
A a = new B();
因此,这里:
List<SomeDummyClass> someDummyClasses = a.foo();
而这一汇编甚至不会通过
请注意,您的问题并不特定于重写方法。
声明一个方法(该方法还生成有关未选中强制转换的警告):
公共静态列表getListOfAny(){
返回(列表)新的ArrayList();
}
你可以用同样的方式使用它:
List<String> listOfAny = getListOfAny();
List listofay=getlistofay();
<> P>这个故事的寓意:<强>不要考虑编译器所产生的未经检查的转换警告,比如化妆品/细节,但要正确处理它们,你可以从泛型带来的编译检查中尽可能多地受益。 我假设Heg感谢答案。我确实无意中忽略了编译器的警告。谢谢你指出这一点。不客气。对于这个故事来说,几天前不可能理解编译器的奇怪行为。事实上,这是由于当前怪异代码的未经检查的转换造成的。最后,我将把IDE中未锁定转换警告的严重性级别提高到error:)+1,以了解编译后的效果。链接不起作用。你能更新一下吗?我同意A
更有意义,如果我在写库的话,我会选择这个选项。我想知道为什么mybatis没有这样做(可能是因为它最终会在许多类型上参数化接口)@LavishKothari这很奇怪。这个链接仍在为我工作。试试这个:
public static <T> List<T> getListOfAny(){
return (List<T>) new ArrayList<Integer>();
}
List<String> listOfAny = getListOfAny();