[英]Why @Autowired raises UnsatisfiedDependencyException, even the class does not implement any interface?
[英]Why does this class compile even though it does not properly implement its interface?
一个List然后为什么代码(下面)编译? 当然MyClass2
应该返回List<Integer>
?
public class Main {
public static void main(final String[] args) {
MyClass myClass = new MyClass();
List list = myClass.getList();
System.out.println(list);
System.out.println(list.get(0).getClass());
MyClass2 myClass2 = new MyClass2();
List list2 = myClass2.getList();
System.out.println(list2);
System.out.println(list2.get(0).getClass());
}
public interface Int1 {
public List getList();
}
public interface Int2 extends Int1 {
@Override
public List<Integer> getList();
}
public static class MyClass implements Int2 {
@Override
public List<Integer> getList() {
return Arrays.asList(1, 2, 3);
}
}
public static class MyClass2 implements Int2 {
@Override
public List getList() {
return Arrays.asList("One", "Two", "Three");
}
}
}
我注意到如果你试图使它成为List<String>
然后你得到一个错误“java:Main.MyClass2不是抽象的,并且不会覆盖Main.Int2中的抽象方法getList()”。 我不太明白为什么你在上面的例子中没有得到这个。
注意:我的项目中的问题的解决方案是使接口本身通用,即Int1<X>
(当然我使用比这更好的名称,它只是一个例子)。
我怀疑,编译器应该为您提供Unchecked转换的警告,而不是将其标记为编译器错误。 让我们理解为什么它会警告你:
您有以下两种方法来实现以满足您实现的接口的合同:
public List getList();
public List<Integer> getList();
现在,如果在您的类中,您只提供第一个方法的实现,它可以处理第二个方法的请求。 您可以返回List<Integer>
,返回类型为List
。 这是因为List<Integer>
在运行时只是一个List
,因为类型擦除 。
但是,如果你只是给第二个方法实现,它将不满足第一个方法的合同。 第一种方法说,它可以返回任何类型的List
,因为它在返回类型中使用了raw类型。 因此,它可以返回List<Integer>
, List<Object>
, List<String>
等等。 但是第二种方法只能返回List<Integer>
。
编译器将在编译时执行此类型检查,它将向您发出警告, List
需要未经检查的转换为List<Integer>
,因为由于类型擦除,转换无论如何都会在运行时成功。
这是类似的情况如下:
List<String> listString = new ArrayList<String>();
List rawList = new ArrayList();
listString = rawList; // Warning: Unchecked conversion
rawList = listString;
推荐阅读 :
答案在JLS 7 5.5.1中。 参考类型铸造 :
给定编译时引用类型S(源)和编译时引用类型T(目标),如果由于以下规则而没有发生编译时错误,则从S到T存在转换转换。
如果S是类类型:
If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs. Furthermore, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types
(§4.5),并且X和Y的擦除相同,发生编译时错误。
在您的情况下, List<Integer>
和List<String>
是可证明的不同参数化类型,它们都具有相同的擦除: List
。
public List<Integer> getList()
的签名与类型擦除后public List getList()
的签名相同。 对于重写方法,您需要覆盖方法作为重写方法的子签名。 如果类型擦除后它们是相同的,那么这里的编译器将决定子类方法是否覆盖接口,并且我们永远不会发生冲突。
从字面上看,由于类型擦除,这没有任何影响:
public interface Int1 {
public List getList();
}
public interface Int2 extends Int1 {
@Override
public List<Integer> getList();
}
在运行时,任何List<X>
将成为List
。 因此,你不要在这里@Override
任何东西。 .getList()
的运行时原型是List getList()
。 您在Int2
参数化List
的事实将被完全忽略。
编译器警告你:
java: Note: Main.java uses unchecked or unsafe operations.
java: Note: Recompile with -Xlint:unchecked for details.
Int2扩展Int1然后List就可以了,
List<String>
不编译,因为它没有在Int1或Int2中定义。
List<Integer>
在
Int2
根据Java规范http://docs.oracle.com/javase/tutorial/java/generics/erasure.html进行类型擦除
所以看起来它与类型擦除有关,它产生警告而不是编译器错误。 我想这就像我之前见过的其他未经检查的转换场景。 感谢人们研究得很好的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.