[英]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.