<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 自限定的類型 在 Java 泛型中,有一個似乎經常性出現的慣用法,它相當令人費解: ```java class SelfBounded<T extends SelfBounded<T>> { // ... ``` 這就像兩面鏡子彼此照向對方所引起的目眩效果一樣,是一種無限反射。**SelfBounded** 類接受泛型參數 **T**,而 **T** 由一個邊界類限定,這個邊界就是擁有 **T** 作為其參數的 **SelfBounded**。 當你首次看到它時,很難去解析它,它強調的是當 **extends** 關鍵字用于邊界與用來創建子類明顯是不同的。 ### 古怪的循環泛型 為了理解自限定類型的含義,我們從這個慣用法的一個簡單版本入手,它沒有自限定的邊界。 不能直接繼承一個泛型參數,但是,可以繼承在其自己的定義中使用這個泛型參數的類。也就是說,可以聲明: ```java // generics/CuriouslyRecurringGeneric.java class GenericType<T> {} public class CuriouslyRecurringGeneric extends GenericType<CuriouslyRecurringGeneric> {} ``` 這可以按照 Jim Coplien 在 C++ 中的*古怪的循環模版模式*的命名方式,稱為古怪的循環泛型(CRG)。“古怪的循環”是指類相當古怪地出現在它自己的基類中這一事實。 為了理解其含義,努力大聲說:“我在創建一個新類,它繼承自一個泛型類型,這個泛型類型接受我的類的名字作為其參數。”當給出導出類的名字時,這個泛型基類能夠實現什么呢?好吧,Java 中的泛型關乎參數和返回類型,因此它能夠產生使用導出類作為其參數和返回類型的基類。它還能將導出類型用作其域類型,盡管這些將被擦除為 **Object** 的類型。下面是表示了這種情況的一個泛型類: ```java // generics/BasicHolder.java public class BasicHolder<T> { T element; void set(T arg) { element = arg; } T get() { return element; } void f() { System.out.println(element.getClass().getSimpleName()); } } ``` 這是一個普通的泛型類型,它的一些方法將接受和產生具有其參數類型的對象,還有一個方法在其存儲的域上執行操作(盡管只是在這個域上執行 **Object** 操作)。 我們可以在一個古怪的循環泛型中使用 **BasicHolder**: ```java // generics/CRGWithBasicHolder.java class Subtype extends BasicHolder<Subtype> {} public class CRGWithBasicHolder { public static void main(String[] args) { Subtype st1 = new Subtype(), st2 = new Subtype(); st1.set(st2); Subtype st3 = st1.get(); st1.f(); } } /* Output: Subtype */ ``` 注意,這里有些東西很重要:新類 **Subtype** 接受的參數和返回的值具有 **Subtype** 類型而不僅僅是基類 **BasicHolder** 類型。這就是 CRG 的本質:基類用導出類替代其參數。這意味著泛型基類變成了一種其所有導出類的公共功能的模版,但是這些功能對于其所有參數和返回值,將使用導出類型。也就是說,在所產生的類中將使用確切類型而不是基類型。因此,在**Subtype** 中,傳遞給 `set()` 的參數和從 `get()` 返回的類型都是確切的 **Subtype**。 ### 自限定 **BasicHolder** 可以使用任何類型作為其泛型參數,就像下面看到的那樣: ```java // generics/Unconstrained.java // (c)2017 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. class Other {} class BasicOther extends BasicHolder<Other> {} public class Unconstrained { public static void main(String[] args) { BasicOther b = new BasicOther(); BasicOther b2 = new BasicOther(); b.set(new Other()); Other other = b.get(); b.f(); } } /* Output: Other */ ``` 限定將采取額外的步驟,強制泛型當作其自身的邊界參數來使用。觀察所產生的類可以如何使用以及不可以如何使用: ```java // generics/SelfBounding.java class SelfBounded<T extends SelfBounded<T>> { T element; SelfBounded<T> set(T arg) { element = arg; return this; } T get() { return element; } } class A extends SelfBounded<A> {} class B extends SelfBounded<A> {} // Also OK class C extends SelfBounded<C> { C setAndGet(C arg) { set(arg); return get(); } } class D {} // Can't do this: // class E extends SelfBounded<D> {} // Compile error: // Type parameter D is not within its bound // Alas, you can do this, so you cannot force the idiom: class F extends SelfBounded {} public class SelfBounding { public static void main(String[] args) { A a = new A(); a.set(new A()); a = a.set(new A()).get(); a = a.get(); C c = new C(); c = c.setAndGet(new C()); } } ``` 自限定所做的,就是要求在繼承關系中,像下面這樣使用這個類: ```java class A extends SelfBounded<A>{} ``` 這會強制要求將正在定義的類當作參數傳遞給基類。 自限定的參數有何意義呢?它可以保證類型參數必須與正在被定義的類相同。正如你在 B 類的定義中所看到的,還可以從使用了另一個 **SelfBounded** 參數的 **SelfBounded** 中導出,盡管在 **A** 類看到的用法看起來是主要的用法。對定義 **E** 的嘗試說明不能使用不是 **SelfBounded** 的類型參數。 遺憾的是, **F** 可以編譯,不會有任何警告,因此自限定慣用法不是可強制執行的。如果它確實很重要,可以要求一個外部工具來確保不會使用原生類型來替代參數化類型。 注意,可以移除自限定這個限制,這樣所有的類仍舊是可以編譯的,但是 **E** 也會因此而變得可編譯: ```java // generics/NotSelfBounded.java public class NotSelfBounded<T> { T element; NotSelfBounded<T> set(T arg) { element = arg; return this; } T get() { return element; } } class A2 extends NotSelfBounded<A2> {} class B2 extends NotSelfBounded<A2> {} class C2 extends NotSelfBounded<C2> { C2 setAndGet(C2 arg) { set(arg); return get(); } } class D2 {} // Now this is OK: class E2 extends NotSelfBounded<D2> {} ``` 因此很明顯,自限定限制只能強制作用于繼承關系。如果使用自限定,就應該了解這個類所用的類型參數將與使用這個參數的類具有相同的基類型。這會強制要求使用這個類的每個人都要遵循這種形式。 還可以將自限定用于泛型方法: ```java // generics/SelfBoundingMethods.java // (c)2017 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. public class SelfBoundingMethods { static <T extends SelfBounded<T>> T f(T arg) { return arg.set(arg).get(); } public static void main(String[] args) { A a = f(new A()); } } ``` 這可以防止這個方法被應用于除上述形式的自限定參數之外的任何事物上。 ### 參數協變 自限定類型的價值在于它們可以產生*協變參數類型*——方法參數類型會隨子類而變化。 盡管自限定類型還可以產生與子類類型相同的返回類型,但是這并不十分重要,因為*協變返回類型*是在 Java 5 引入: ```java // generics/CovariantReturnTypes.java class Base {} class Derived extends Base {} interface OrdinaryGetter { Base get(); } interface DerivedGetter extends OrdinaryGetter { // Overridden method return type can vary: @Override Derived get(); } public class CovariantReturnTypes { void test(DerivedGetter d) { Derived d2 = d.get(); } } ``` **DerivedGetter** 中的 `get()` 方法覆蓋了 **OrdinaryGetter** 中的 `get()` ,并返回了一個從 `OrdinaryGetter.get()` 的返回類型中導出的類型。盡管這是完全合乎邏輯的事情(導出類方法應該能夠返回比它覆蓋的基類方法更具體的類型)但是這在早先的 Java 版本中是不合法的。 自限定泛型事實上將產生確切的導出類型作為其返回值,就像在 `get()` 中所看到的一樣: ```java // generics/GenericsAndReturnTypes.java interface GenericGetter<T extends GenericGetter<T>> { T get(); } interface Getter extends GenericGetter<Getter> {} public class GenericsAndReturnTypes { void test(Getter g) { Getter result = g.get(); GenericGetter gg = g.get(); // Also the base type } } ``` 注意,這段代碼不能編譯,除非是使用囊括了協變返回類型的 Java 5。 然而,在非泛型代碼中,參數類型不能隨子類型發生變化: ```java // generics/OrdinaryArguments.java class OrdinarySetter { void set(Base base) { System.out.println("OrdinarySetter.set(Base)"); } } class DerivedSetter extends OrdinarySetter { void set(Derived derived) { System.out.println("DerivedSetter.set(Derived)"); } } public class OrdinaryArguments { public static void main(String[] args) { Base base = new Base(); Derived derived = new Derived(); DerivedSetter ds = new DerivedSetter(); ds.set(derived); // Compiles--overloaded, not overridden!: ds.set(base); } } /* Output: DerivedSetter.set(Derived) OrdinarySetter.set(Base) */ ``` `set(derived)` 和 `set(base)` 都是合法的,因此 `DerivedSetter.set()` 沒有覆蓋 `OrdinarySetter.set()` ,而是重載了這個方法。從輸出中可以看到,在 **DerivedSetter** 中有兩個方法,因此基類版本仍舊是可用的,因此可以證明它被重載過。 但是,在使用自限定類型時,在導出類中只有一個方法,并且這個方法接受導出類型而不是基類型為參數: ```java // generics/SelfBoundingAndCovariantArguments.java interface SelfBoundSetter<T extends SelfBoundSetter<T>> { void set(T arg); } interface Setter extends SelfBoundSetter<Setter> {} public class SelfBoundingAndCovariantArguments { void testA(Setter s1, Setter s2, SelfBoundSetter sbs) { s1.set(s2); //- s1.set(sbs); // error: method set in interface SelfBoundSetter<T> // cannot be applied to given types; // s1.set(sbs); // ^ // required: Setter // found: SelfBoundSetter // reason: argument mismatch; // SelfBoundSetter cannot be converted to Setter // where T is a type-variable: // T extends SelfBoundSetter<T> declared in // interface SelfBoundSetter // 1 error } } ``` 編譯器不能識別將基類型當作參數傳遞給 `set()` 的嘗試,因為沒有任何方法具有這樣的簽名。實際上,這個參數已經被覆蓋。 如果不使用自限定類型,普通的繼承機制就會介入,而你將能夠重載,就像在非泛型的情況下一樣: ```java // generics/PlainGenericInheritance.java class GenericSetter<T> { // Not self-bounded void set(T arg) { System.out.println("GenericSetter.set(Base)"); } } class DerivedGS extends GenericSetter<Base> { void set(Derived derived) { System.out.println("DerivedGS.set(Derived)"); } } public class PlainGenericInheritance { public static void main(String[] args) { Base base = new Base(); Derived derived = new Derived(); DerivedGS dgs = new DerivedGS(); dgs.set(derived); dgs.set(base); // Overloaded, not overridden! } } /* Output: DerivedGS.set(Derived) GenericSetter.set(Base) */ ``` 這段代碼在模仿 **OrdinaryArguments.java**;在那個示例中,**DerivedSetter** 繼承自包含一個 `set(Base)` 的**OrdinarySetter** 。而這里,**DerivedGS** 繼承自泛型創建的也包含有一個 `set(Base)`的 `GenericSetter<Base>`。就像 **OrdinaryArguments.java** 一樣,你可以從輸出中看到, **DerivedGS** 包含兩個 `set()` 的重載版本。如果不使用自限定,將重載參數類型。如果使用了自限定,只能獲得方法的一個版本,它將接受確切的參數類型。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看