簡體   English   中英

如何在Java中用內部類實例化遞歸綁定泛型?

[英]How to instantiate recursive bound generics with inner class in Java?

我想將內部類作為參數的泛型外部類。 我期待,我將從基類派生出來,或者使用它的內部,或者從內部派生出來。 在每個級別,我都希望從當前的派生水平開始限制內部類別的使用。

不幸的是,我在使用模式時會遇到各種錯誤和警告,這使我無法想象,如何使用它。

package tests.java;

public class Try_GenericInnerRecursion {

    // base class, consisting of outer and inner parts
    public static class Outer1<E extends Outer1<E>.Inner1> {
        public class Inner1 {
        }

        public void addElement(E e) {
            System.out.println("Added " + e.toString());
        }
    }

    // extending outer, but not inner
    public static class Outer2<E extends Outer1<E>.Inner1> extends Outer1<E>{

    }

    // extending both outer and inner
    public static class Outer3<E extends Outer3<E>.Inner3> extends Outer1<E>{
        public class Inner3 extends Inner1 {
        }
    }

    // extending both outer and inner and stopping extension
    public static class Outer4 extends Outer1<Outer4.Inner4> {
        public class Inner4 extends Outer1<Inner4>.Inner1 {
        }
    }



    // instantiating
    public static void main(String[] args) {

        Outer1<Outer1.Inner1> a1; // WARNING: Outer1.Inner1 is a raw type

        a1 = new Outer1<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type

        Outer1<?> a2; // OK 

        a2 = new Outer1<?>(); // ERROR: Cannot instantiate the type Outer1<?>

        Outer1<Outer1<?>.Inner1> a3; // ERROR: Bound mismatch: The type Outer1<?>.Inner1 is not a valid substitute for the bounded parameter <E extends Outer1<E>.Inner1> of the type Outer1<E>

    Outer1<? extends Outer1<?>.Inner1> a4; // OK

    a4 = new Outer1<Outer1.Inner1>(); // ERROR: Type mismatch

            Outer2<Outer1.Inner1> b1; // WARNING: Outer1.Inner1 is a raw type

            b1 = new Outer2<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type

        // and so on
    }

}

我該如何正確使用這種模式?

我相信你可以做到

    DerivedCorpus1<?>

在通配符捕獲期間,它變成了

    DerivedCorpus1<x> where x extends Corpus<x>.Element

哪個是正確的。

在你的例子中

    DerivedCorpus1<? extends Corpus<?>.Element>

在通配符捕獲期間,它變成了

    DerivedCorpus1<x> where x extends Corpus<x>.Element
                        and x extends Corpus<?>.Element

顯然, extends Corpus<?>.Element子句是多余的。

Outer1<Outer1.Inner1> a1; // WARNING: Outer1.Inner1 is a raw type

實際上,我得到“類型參數Outer1.Inner1不在類型變量E`的范圍內”。

Outer1.Inner1是原始類型,因為Outer1是原始類型。 要使用非原始類型,您需要編寫Outer1<something>.Inner1 但是, something也必須依次擴展Outer1<something>.Inner1 為了像這樣進行遞歸,你需要一個命名的遞歸類型。 不幸的是,由於Inner1是一個非靜態內部類,它有一個對Outer1實例的隱式引用,因此任何擴展它的類都需要有一個封閉的Outer1實例。 Outer4Inner4基本上都是這樣做的。

Outer4 a1 = new Outer4(); // compiles fine

a2 = new Outer1<?>(); // ERROR: Cannot instantiate the type Outer1<?>

你永遠不能做new something<?>()

Outer1<Outer1<?>.Inner1> a3; // ERROR: Bound mismatch: The type Outer1<?>.Inner1 is not a valid substitute for the bounded parameter <E extends Outer1<E>.Inner1> of the type Outer1<E>

這是真的。 Outer1<?>.Inner1不是Outer1<E>.Inner1的子類型Outer1<E>.Inner1 - 它是另一種方式Outer1<E>.Inner1Outer1<?>.Inner1的子類型Outer1<?>.Inner1 這就像ArrayList<?>不是ArrayList<String>的子類型一樣; 反過來說。

Outer1<? extends Outer1<?>.Inner1> a4; // OK

這沒關系,因為你在頂層有一個通配符,你的通配符的邊界與類型參數E的綁定相交。 事實上,任何滿足E的原始界限的東西都必須滿足這個界限,所以這個界限是沒用的,這與Outer1<?> a2; 以上。

a4 = new Outer1<Outer1.Inner1>(); // ERROR: Type mismatch

由於其他原因導致a1不起作用的原因( Outer1.Inner1不滿足E的界限), Outer1.Inner1不起作用。 它還不滿足你的界限( Outer1<?>.Inner1 )我相信。

Outer2<Outer1.Inner1> b1; // WARNING: Outer1.Inner1 is a raw type

出於同樣的原因,這實際上給出了與a1相同的錯誤

通用規范

在我繼續討論實例化問題之前,我修改了你的通用定義:

Outer1<E extends Outer1<E>.Inner1>

Outer1基本上應該包含Inner1類型的元素或它的任何子類。 因此,Outer1對象的類型不相關,可以使用以下代碼替換:

Outer1<E extends Outer1<?>.Innter1>

此外,使用上面提到的稍微修改了擴展類。

實例化

對於對象的實例化,您說明如下:

 Outer1<Outer1.Inner1> a1; // WARNING: Outer1.Inner1 is a raw type a1 = new Outer1<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type 

正如newacct已經提到的,雖然在實例化對象時沒有指定任何類型,但是Outer1被聲明為泛型類型。 因此,代碼應更改為以下代碼:

Outer1<Outer1<?>.Innter1> a1;           // or simply Outer1<?> a1;
a1 = new Outer1<Outer1<?>.Innter1>();   // or simply a1 = new Outer1<>();

類似於分配將基類擴展為該基類類型的類。

您可以使用泛型類型定義指定實例將包含的元素類型。

像這樣的聲明

Outer1<Outer1<?>.Innter1> test;

將接受任何擴展Outer1實例,它們也匹配泛型類型。 這意味着您只能分配

test = new Outer1<Outer1<?>.Inner1>();
test = new Outer2<Outer2<?>.Inner1>();

它,但不是Outer3甚至Outer4

即使您進一步修改代碼以添加fe

public static class Outer5<E extends Outer1<?>.Inner1> extends Outer1<E>{
    public class Inner5 extends Inner1 {
    }
}

你只能添加

test = new Outer5<Outer5<?>.Inner1>();

但不是

test = new Outer5<Outer5<?>.Inner5>(); // FAILS!

Inner1定義為類型參數的東西。

但是,這個問題實際上是一個非常簡單的解決方案。 如果您像這樣定義對象:

Outer1<? extends Outer1<?>.Inner1> test2;

你實際上可以做以下事情:

test2 = new Outer1<Outer1<?>.Inner1>();
test2 = new Outer2<Outer2<?>.Inner1>();
test2 = new Outer3<Outer3<?>.Inner3>();
test2 = new Outer4();
test2 = new Outer5<Outer1<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner5>();

正如您現在明確告訴編譯器允許Inner1類型本身或其任何擴展。

我已經更新了你的代碼並添加了一些新的賦值,以驗證所做的更改實際上不會產生任何編譯錯誤或警告,除了redundant type arguments in new expressionredundant type arguments in new expression因為顯式指定了類型參數而不是使用菱形運算符<>

public class GenericInnerRecursion
{
    // base class, consisting of outer and inner parts
    public static class Outer1<E extends Outer1<?>.Inner1> {
        public class Inner1 {
        }

        public void addElement(E e) {
            System.out.println("Added " + e.toString());
        }
    }

    // extending outer, but not inner
    public static class Outer2<E extends Outer1<?>.Inner1> extends Outer1<E>{

    }

    // extending both outer and inner
    public static class Outer3<E extends Outer3<?>.Inner3> extends Outer1<E>{
        public class Inner3 extends Inner1 {
        }
    }

    // extending both outer and inner and stopping extension
    public static class Outer4 extends Outer1<Outer4.Inner4> {
        public class Inner4 extends Outer1<Inner4>.Inner1 {
        }
    }

    public static class Outer5<E extends Outer1<?>.Inner1> extends Outer1<E>{
        public class Inner5 extends Inner1 {
        }
    }


    // instantiating
    public static void main(String[] args) {

        Outer1<Outer1<?>.Inner1> a1;
        a1 = new Outer1<Outer1<?>.Inner1>();

        Outer1<?> a2;
        a2 = new Outer1<>();

        Outer1<Outer1<?>.Inner1> a3; 

        Outer1<? extends Outer1<?>.Inner1> a4;
        a4 = new Outer1<Outer1<?>.Inner1>();

        Outer2<Outer1<?>.Inner1> b1;
        b1 = new Outer2<Outer1<?>.Inner1>();

        // and so on

        // assigning extension-classes to the parent-class
        Outer1<Outer1<?>.Inner1> c1;
        c1 = new Outer2<Outer2<?>.Inner1>();
        // assigning inner-extension-classes to parent-class
        Outer1<Outer3<?>.Inner3> c2;
        c2 = new Outer3<Outer3<?>.Inner3>();
        // assigning extension class without specified generics to parent class
        Outer1<Outer4.Inner4> c3;
        c3 = new Outer4();

        Outer1<Outer1<?>.Inner1> test;
        test = new Outer1<>();
        test = new Outer2<>();
        test = new Outer5<Outer5<?>.Inner1>();

        Outer1<? extends Outer1<?>.Inner1> test2;
        test2 = new Outer1<Outer1<?>.Inner1>();
        test2 = new Outer2<Outer2<?>.Inner1>();
        test2 = new Outer3<Outer3<?>.Inner3>();
        // new Outer3<Outer3<?>.Inner1>(); not possible as generic type extends Outer3<?>.Inner3 and not Outer1<?>.Inner1!
        test2 = new Outer4();
        test2 = new Outer5<Outer1<?>.Inner1>();
        test2 = new Outer5<Outer5<?>.Inner1>();
        test2 = new Outer5<Outer5<?>.Inner5>();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM