2017-06-30 25 views
0

1)爲什麼obj4,obj6,obj7給編譯錯誤,並且obj5很好?我在哪裏可以閱讀有關規則,調整使用這種通用耦合外層內部類?我沒有發現任何直接的問題。管理實例化泛型外部類及其內部通用內部類的實例並聲明相應引用的規則是什麼?

當我沒有在obj3中爲Inner類提供任何類型參數時,它是好的(而Inner類需要給它的類型爲S的fld3字段的東西),但是當我這樣做並且不提供類外部類 - 它不會編譯(obj4) - 雖然對象可能暗示...

2)此外,爲什麼obj10編譯好,但obj11失敗?在obj10行我也寫outerInstance.new內部<>(),暗示內部S是對象。但是,這是不是內部問​​題,但同樣的「貓膩」是外部問題...

 //in Class A of package com.sth 
     public class MyGen<T> { 
      T fld1; 

      class GenInner<S> { 
       T fld2; 
       S fld3; 
      } 

       // within main of Class Driver of same package com.sth 
       MyGen.GenInner obj1 = new MyGen<String>().new GenInner<Integer>(); 
       MyGen.GenInner obj2 = new MyGen<String>().new GenInner<>(); 
       MyGen.GenInner obj3 = new MyGen<String>().new GenInner(); 
       //MyGen.GenInner obj4 = new MyGen().new GenInner<String>(); //ERR ! 
       MyGen.GenInner obj5 = new MyGen<>().new GenInner<String>(); 

       //MyGen<String>.GenInner obj6; // ERR 
       //MyGen.GenInner<String> obj7; // ERR 
       MyGen<String>.GenInner<Integer> obj8; 
       MyGen.GenInner obj9;  


    MyGen<String>.GenInner<Integer> obj10 = new MyGen<String>().new GenInner<>(); 

    //Type mismatch: cannot convert from MyGen<Object>.GenInner<Integer> to MyGen<String>.GenInner<Integer> 
    //MyGen<String>.GenInner<Integer> obj11 = new MyGen<>().new GenInner<Integer>(); // ERR! 

這些答案涉及到我的問題,但沒有提供任何線索:

  1. Answer 1
  2. Answer 2
  3. Answer 3
  4. Answer 4
  5. Answer 5
+0

Java 8也拒絕'obj3':「形式不正確,某些參數丟失」。 –

+0

奇怪,但我的Eclipse編譯器爲Java SE8編譯obj3行很好,並且在運行時沒有問題! P.S .: MyGen.GenInner obj3 = new MyGen ().new GenInner(); – LrnBoy

+0

我想我應該更具體一些:OpenJDK 8的編譯器拒絕分配給'obj3'的類實例化表達式。 OpenJDK也是Oracle品牌JDK的基礎,因此它具有很大的優勢。我不認爲拒絕它是正確的,@ Radiodef的優秀答案儘管如此,但我認爲這樣寫代碼是不明智的。除少數例外,新代碼不應該使用原始類型(也不要嘗試使用稀有類型)。 –

回答

1

不編譯的例子大多是罕見類型的例子。 (此外,如由John在評論所指出的,例如obj3不應任一編譯。)

raw type一個是通過使用通用型不具有伴隨的類型參數列表(如例如Set形成的類型,如與例如Set<Float>相反)。 A 罕見類型是當你有一個通用的外部類和通用的內部類,其中一個是原始的,另一個不是。

JLS 4.8 Raw Types摘自:

更準確地說,原始類型被定義爲是以下之一:

  • ,其通過採取通用類型聲明的名稱,而不形成的引用類型一個隨附的類型參數列表。

  • 元素類型爲原始類型的數組類型。

  • 原始類型R未從R一個超類或超繼承的一個非static構件類型。

(請注意,在大膽一點意味着,如果你有一個原始類型MyGen,則其非static成員類GenInner還必須生吃,所以作爲例如MyGen.GenInner<String>沒有這樣的事情。)

以上的規則的另一個意義是一個通用的內部類原始類型的可以本身只被用作原始類型:

class Outer<T>{ 
    class Inner<S> { 
     S s; 
    } 
} 

這是不可能訪問Inner爲部分生型(「罕見」型):

Outer.Inner<Double> x = null; // illegal 
Double d = x.s; 

因爲Outer本身是生的,因此這樣被其所有內部類包括Inner,因此它不可能PA連接到Inner的任何類型參數。

這是一個編譯時錯誤傳遞類型參數到未從其超類或超接口繼承的原始類型的非static型部件。

嘗試將參數化類型的類型成員用作原始類型是編譯時錯誤。

這意味着,在「罕見」類型的禁令延伸至合格類型是參數化的情況下,但我們嘗試使用內部類作爲原料類型:

Outer<Integer>.Inner x = null; // illegal 

這是相反的上面討論的情況。這種半烤型沒有實際的理由。在遺留代碼中,不使用類型參數。在非遺留代碼中,我們應該正確使用泛型,並傳遞所有必需的類型參數。

obj11 = new MyGen<>().new GenInner<Integer>()的例子不是一種罕見的類型。它看起來像是鑽石類型推斷的常規失敗,因爲表達式new MyGen<>()未分配給任何東西。在沒有任務的情況下,通常假定Object。 (更多技術上將是任何的類型變量是,這是Object在這種情況下,上界。)


此外,雖然不直接相關的手頭上的問題,以下是僅有的兩種形式這實際上應該在新的代碼中使用:

MyGen<String>.GenInner<Integer> ok1 = new MyGen<String>().new GenInner<Integer>(); 
MyGen<String>.GenInner<Integer> ok2 = new MyGen<String>().new GenInner<>(); 

所有的人(其中編譯)的使用原始類型和原始類型氣餒。

相關問題