<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## Chapter 4. Classes and Interfaces(類和接口) ### Item 20: Prefer interfaces to abstract classes(接口優于抽象類) Java has two mechanisms to define a type that permits multiple implementations: interfaces and abstract classes. Since the introduction of default methods for interfaces in Java 8 [JLS 9.4.3], both mechanisms allow you to provide implementations for some instance methods. A major difference is that to implement the type defined by an abstract class, a class must be a subclass of the abstract class. Because Java permits only single inheritance, this restriction on abstract classes severely constrains their use as type definitions.Any class that defines all the required methods and obeys the general contract is permitted to implement an interface, regardless of where the class resides in the class hierarchy. Java 有兩種機制來定義允許多種實現的類型:接口和抽象類。由于 Java 8 [JLS 9.4.3]中引入了接口的默認方法,這兩種機制都允許你為一些實例方法提供實現。一個主要區別是,一個類要實現抽象類定義的類型,該類必須是抽象類的子類。因為 Java 只允許單一繼承,這種限制對抽象類而言嚴重制約了它們作為類型定義的使用。任何定義了所有必需的方法并遵守通用約定的類都允許實現接口,而不管該類駐留在類層次結構中何處。 **譯注:** **1、抽象類的局限:一個類要實現抽象類定義的類型,該類必須是抽象類的子類。因為 Java 只允許單一繼承,這種限制對抽象類而言嚴重制約了它們作為類型定義的使用。** **2、接口的優點:任何定義了所有必需的方法并遵守通用約定的類都允許實現接口,而不管該類駐留在類層次結構中何處。** **Existing classes can easily be retrofitted to implement a new interface.** All you have to do is to add the required methods, if they don’t yet exist, and to add an implements clause to the class declaration. For example, many existing classes were retrofitted to implement the Comparable, Iterable, and Autocloseable interfaces when they were added to the platform. Existing classes cannot, in general, be retrofitted to extend a new abstract class. If you want to have two classes extend the same abstract class, you have to place it high up in the type hierarchy where it is an ancestor of both classes. Unfortunately,this can cause great collateral damage to the type hierarchy, forcing all descendants of the new abstract class to subclass it, whether or not it is appropriate. **可以很容易地對現有類進行改造,以實現新的接口。** 你所要做的就是添加所需的方法(如果它們還不存在的話),并向類聲明中添加一個 implements 子句。例如,許多現有的類在添加到 JDK 時進行了修改,以實現 Comparable、Iterable 和 Autocloseable 接口。一般來說,現有的類不能被修改以擴展新的抽象類。如果你想讓兩個類擴展同一個抽象類,你必須把它放在類型層次結構的高層,作為兩個類的祖先。不幸的是,這可能會對類型層次結構造成巨大的附帶損害,迫使新抽象類的所有后代對其進行子類化,無論它是否合適。 **Interfaces are ideal for defining mixins.** Loosely speaking, a mixin is a type that a class can implement in addition to its “primary type,” to declare that it provides some optional behavior. For example, Comparable is a mixin interface that allows a class to declare that its instances are ordered with respect to other mutually comparable objects. Such an interface is called a mixin because it allows the optional functionality to be “mixed in” to the type’s primary functionality. Abstract classes can’t be used to define mixins for the same reason that they can’t be retrofitted onto existing classes: a class cannot have more than one parent, and there is no reasonable place in the class hierarchy to insert a mixin. **接口是定義 mixin(混合類型)的理想工具。** 粗略地說,mixin 是類除了「基本類型」之外還可以實現的類型,用于聲明它提供了一些可選的行為。例如,Comparable 是一個 mixin 接口,它允許類的實例可以與其他的可相互比較的對象進行排序。這樣的接口稱為 mixin,因為它允許可選功能「混合」到類型的主要功能中。抽象類不能用于定義 mixin,原因與它們不能被修改到現有類相同:一個類不能有多個父類,而且在類層次結構中沒有插入 mixin 的合理位置。 **Interfaces allow for the construction of nonhierarchical type frameworks.** Type hierarchies are great for organizing some things, but other things don’t fall neatly into a rigid hierarchy. For example, suppose we have an interface representing a singer and another representing a songwriter: **接口允許構造非層次化類型框架。** 類型層次結構對于組織一些事情很好,但是其他事情不能整齊地歸入嚴格的層次結構。例如,假設我們有一個代表歌手的接口和另一個代表詞曲作者的接口: ``` public interface Singer { AudioClip sing(Song s); } public interface Songwriter { Song compose(int chartPosition); } ``` In real life, some singers are also songwriters. Because we used interfaces rather than abstract classes to define these types, it is perfectly permissible for a single class to implement both Singer and Songwriter. In fact, we can define a third interface that extends both Singer and Songwriter and adds new methods that are appropriate to the combination: 在現實生活中,一些歌手也是詞曲作者。因為我們使用接口而不是抽象類來定義這些類型,所以完全允許單個類同時實現歌手和詞曲作者。事實上,我們可以定義第三個接口,擴展歌手和詞曲作者,并添加適合這種組合的新方法: ``` public interface SingerSongwriter extends Singer, Songwriter { AudioClip strum(); void actSensitive(); } ``` You don’t always need this level of flexibility, but when you do, interfaces are a lifesaver. The alternative is a bloated class hierarchy containing a separate class for every supported combination of attributes. If there are n attributes in the type system, there are 2n possible combinations that you might have to support. This is what’s known as a combinatorial explosion. Bloated class hierarchies can lead to bloated classes with many methods that differ only in the type of their arguments because there are no types in the class hierarchy to capture common behaviors. 你并不總是需要這種級別的靈活性,但是當你需要時,接口就是救星。另一種選擇是一個臃腫的類層次結構,它為每個受支持的屬性組合包含一個單獨的類。如果類型系統中有 n 個屬性,那么可能需要支持 2<sup>n</sup>種組合。這就是所謂的組合爆炸。臃腫的類層次結構可能導致類也臃腫,其中許多方法只在其參數的類型上有所不同,因為類層次結構中沒有類型來捕獲公共行為。 Interfaces enable safe, powerful functionality enhancements via the wrapper class idiom (Item 18). If you use abstract classes to define types, you leave the programmer who wants to add functionality with no alternative but inheritance. The resulting classes are less powerful and more fragile than wrapper classes. 通過 [Item-18](/Chapter-4/Chapter-4-Item-18-Favor-composition-over-inheritance.md) 介紹的包裝類,接口能夠支持安全、強大的功能增強。如果你使用抽象類來定義類型,那么希望添加功能的程序員除了繼承之外別無選擇。最終生成的類不如包裝類強大,也更脆弱。 When there is an obvious implementation of an interface method in terms of other interface methods, consider providing implementation assistance to programmers in the form of a default method. For an example of this technique, see the removeIf method on page 104. If you provide default methods, be sure to document them for inheritance using the @implSpec Javadoc tag (Item 19). 如果接口方法的實現與其他接口方法類似,那么可以考慮以默認方法的形式為程序員提供實現幫助。有關此技術的示例,請參閱第 104 頁的 removeIf 方法。如果提供了默認方法,請使用 `@implSpec` 標簽,并確保在文檔中記錄他們的繼承關系([Item-19](/Chapter-4/Chapter-4-Item-19-Design-and-document-for-inheritance-or-else-prohibit-it.md))。 There are limits on how much implementation assistance you can provide with default methods. Although many interfaces specify the behavior of Object methods such as equals and hashCode, you are not permitted to provide default methods for them. Also, interfaces are not permitted to contain instance fields or nonpublic static members (with the exception of private static methods). Finally, you can’t add default methods to an interface that you don’t control. 默認方法為實現提供的幫助有限。盡管許多接口指定了諸如 equals 和 hashCode 等對象方法的行為,但是不允許為它們提供默認方法。此外,接口不允許包含實例字段或非公共靜態成員(私有靜態方法除外)。最后,你不能向你不控制的接口添加默認方法。 You can, however, combine the advantages of interfaces and abstract classes by providing an abstract skeletal implementation class to go with an interface. The interface defines the type, perhaps providing some default methods, while the skeletal implementation class implements the remaining non-primitive interface methods atop the primitive interface methods. Extending a skeletal implementation takes most of the work out of implementing an interface. This is the Template Method pattern [Gamma95]. 但是,你可以通過提供一個抽象骨架實現類來結合接口和抽象類的優點。接口定義了類型,可能提供了一些默認方法,而骨架實現類在基本接口方法之上實現了其余的非基本接口方法。擴展骨架實現需要完成實現接口的大部分工作。這是模板方法模式 [Gamma95]。 By convention, skeletal implementation classes are called AbstractInterface, where Interface is the name of the interface they implement. For example, the Collections Framework provides a skeletal implementation to go along with each main collection interface: AbstractCollection, AbstractSet, AbstractList, and AbstractMap. Arguably it would have made sense to call them SkeletalCollection, SkeletalSet, SkeletalList, and SkeletalMap, but the Abstract convention is now firmly established. When properly designed, skeletal implementations (whether a separate abstract class, or consisting solely of default methods on an interface) can make it very easy for programmers to provide their own implementations of an interface. For example, here’s a static factory method containing a complete, fully functional List implementation atop AbstractList: 按照慣例,骨架實現類稱為 AbstractInterface,其中 Interface 是它們實現的接口的名稱。例如,Collections Framework 提供了一個骨架實現來配合每個主要的集合接口:AbstractCollection、AbstractSet、AbstractList 和 AbstractMap。可以說,將它們稱為 SkeletalCollection、SkeletalSet、SkeletalList 和 SkeletalMap 是有意義的,但 Abstract 的用法現在已經根深蒂固。如果設計得當,骨架實現(無論是單獨的抽象類,還是僅僅由接口上的默認方法組成)可以使程序員非常容易地提供他們自己的接口實現。例如,這里有一個靜態工廠方法,它在 AbstractList 上包含一個完整的、功能完整的 List 實現: ``` // Concrete implementation built atop skeletal implementation static List<Integer> intArrayAsList(int[] a) { Objects.requireNonNull(a); // The diamond operator is only legal here in Java 9 and later // If you're using an earlier release, specify <Integer> return new AbstractList<>() { @Override public Integer get(int i) { return a[i]; // Autoboxing (Item 6) } @Override public Integer set(int i, Integer val) { int oldVal = a[i]; a[i] = val; // Auto-unboxing return oldVal; // Autoboxing } @Override public int size() { return a.length; } }; } ``` When you consider all that a List implementation does for you, this example is an impressive demonstration of the power of skeletal implementations. Incidentally, this example is an Adapter [Gamma95] that allows an int array to be viewed as a list of Integer instances. Because of all the translation back and forth between int values and Integer instances (boxing and unboxing), its performance is not terribly good. Note that the implementation takes the form of an anonymous class (Item 24). 當你考慮到 List 實現為你做的所有事情時,這個例子是一個令人印象深刻的演示,體現了骨架實現的強大功能。順便說一句,這個示例是一個 Adapter(適配器)[Gamma95],它允許將 int 數組視為 Integer 實例的 list。因為在 int 值和 Integer 實例(裝箱和拆箱)之間來回轉換,所以它的性能不是很好。注意,實現的形式是匿名類([Item-24](/Chapter-4/Chapter-4-Item-24-Favor-static-member-classes-over-nonstatic.md))。 The beauty of skeletal implementation classes is that they provide all of the implementation assistance of abstract classes without imposing the severe constraints that abstract classes impose when they serve as type definitions. For most implementors of an interface with a skeletal implementation class, extending this class is the obvious choice, but it is strictly optional. If a class cannot be made to extend the skeletal implementation, the class can always implement the interface directly. The class still benefits from any default methods present on the interface itself. Furthermore, the skeletal implementation can still aid the implementor’s task. The class implementing the interface can forward invocations of interface methods to a contained instance of a private inner class that extends the skeletal implementation. This technique, known as simulated multiple inheritance, is closely related to the wrapper class idiom discussed in Item 18. It provides many of the benefits of multiple inheritance, while avoiding the pitfalls. 骨架實現類的美妙之處在于,它們提供了抽象類的所有實現幫助,而不像抽象類作為類型定義時那樣受到嚴格的約束。對于具有骨架實現類的接口的大多數實現來說,擴展這個類是顯而易見的選擇,但它并不是必需的。如果不能使類擴展骨架實現,則類總是可以直接實現接口。類仍然受益于接口本身的任何默認方法。此外,骨架實現仍然可以幫助實現人員完成任務。實現接口的類可以將接口方法的調用轉發給擴展骨架實現的私有內部類的包含實例。這種技術稱為模擬多重繼承,與[Item-18](/Chapter-4/Chapter-4-Item-18-Favor-composition-over-inheritance.md)中討論的包裝類密切相關。它提供了多重繼承的許多好處,同時避免了缺陷。 Writing a skeletal implementation is a relatively simple, if somewhat tedious, process. First, study the interface and decide which methods are the primitives in terms of which the others can be implemented. These primitives will be the abstract methods in your skeletal implementation. Next, provide default methods in the interface for all of the methods that can be implemented directly atop the primitives, but recall that you may not provide default methods for Object methods such as equals and hashCode. If the primitives and default methods cover the interface, you’re done, and have no need for a skeletal implementation class. Otherwise, write a class declared to implement the interface, with implementations of all of the remaining interface methods. The class may contain any nonpublic fields ands methods appropriate to the task. 編寫一個骨架實現是一個相對簡單的過程,盡管有點乏味。首先,研究接口并決定哪些方法是基本方法,以便其他方法可以根據它們實現。這些基本方法將是你的骨架實現中的抽象方法。接下來,在接口中為所有可以直接在基本方法之上實現的方法提供默認方法,但請記住,你可能不會為諸如 equals 和 hashCode 之類的對象方法提供默認方法。如果基本方法和默認方法覆蓋了接口,那么就完成了,不需要一個骨架實現類。否則,編寫一個聲明為實現接口的類,并實現所有剩余的接口方法。該類可能包含任何適合于任務的非公共字段和方法。 As a simple example, consider the Map.Entry interface. The obvious primitives are getKey, getValue, and (optionally) setValue. The interface specifies the behavior of equals and hashCode, and there is an obvious implementation of toString in terms of the primitives. Since you are not allowed to provide default implementations for the Object methods, all implementations are placed in the skeletal implementation class: 作為一個簡單的例子,考慮一下 `Map.Entry` 接口。最明顯的基本方法是 getKey、getValue 和(可選的)setValue。該接口指定了 equals 和 hashCode 的行為,并且在基本方法方面有 toString 的明顯實現。由于不允許為對象方法提供默認實現,所有實現都放在骨架實現類中: ``` // Skeletal implementation class public abstract class AbstractMapEntry<K,V> implements Map.Entry<K,V> { // Entries in a modifiable map must override this method @Override public V setValue(V value) { throw new UnsupportedOperationException(); } // Implements the general contract of Map.Entry.equals @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry) o; return Objects.equals(e.getKey(), getKey()) && Objects.equals(e.getValue(), getValue()); } // Implements the general contract of Map.Entry.hashCode @Override public int hashCode() { return Objects.hashCode(getKey())^ Objects.hashCode(getValue()); } @Override public String toString() { return getKey() + "=" + getValue(); } } ``` Note that this skeletal implementation could not be implemented in the Map.Entry interface or as a subinterface because default methods are not permitted to override Object methods such as equals, hashCode, and toString. 注意,這個骨架實現不能在 `Map.Entry` 接口或子接口中實現,因為不允許默認方法覆蓋諸如 equals、hashCode 和 toString 等對象方法。 Because skeletal implementations are designed for inheritance, you should follow all of the design and documentation guidelines in Item 19. For brevity’s sake, the documentation comments were omitted from the previous example, but good documentation is absolutely essential in a skeletal implementation, whether it consists of default methods on an interface or a separate abstract class. 因為骨架實現是為繼承而設計的,所以你應該遵循 [Item-19](/Chapter-4/Chapter-4-Item-19-Design-and-document-for-inheritance-or-else-prohibit-it.md) 中的所有設計和文檔指南。為了簡潔起見,在前面的示例中省略了文檔注釋,但是優秀的文檔對于骨架實現來說是絕對必要的,不管它是由接口上的默認方法還是單獨的抽象類組成。 A minor variant on the skeletal implementation is the simple implementation, exemplified by AbstractMap.SimpleEntry. A simple implementation is like a skeletal implementation in that it implements an interface and is designed for inheritance, but it differs in that it isn’t abstract: it is the simplest possible working implementation. You can use it as it stands or subclass it as circumstances warrant. 骨架實現的一個小變種是簡單實現,例如 `AbstractMap.SimpleEntry`。一個簡單的實現就像一個骨架實現,因為它實現了一個接口,并且是為繼承而設計的,但是它的不同之處在于它不是抽象的:它是最簡單的工作實現。你可以根據它的狀態使用它,也可以根據情況對它進行子類化。 To summarize, an interface is generally the best way to define a type that permits multiple implementations. If you export a nontrivial interface, you should strongly consider providing a skeletal implementation to go with it. To the extent possible, you should provide the skeletal implementation via default methods on the interface so that all implementors of the interface can make use of it. That said, restrictions on interfaces typically mandate that a skeletal implementation take the form of an abstract class. 總之,接口通常是定義允許多種實現的類型的最佳方法。如果導出了一個重要的接口,則應該強烈考慮提供一個骨架實現。盡可能地,你應該通過接口上的默認方法提供骨架實現,以便接口的所有實現者都可以使用它。也就是說,對接口的限制通常要求框架實現采用抽象類的形式。 --- **[Back to contents of the chapter(返回章節目錄)](/Chapter-4/Chapter-4-Introduction.md)** - **Previous Item(上一條目):[Item 19: Design and document for inheritance or else prohibit it(繼承要設計良好并且具有文檔,否則禁止使用)](/Chapter-4/Chapter-4-Item-19-Design-and-document-for-inheritance-or-else-prohibit-it.md)** - **Next Item(下一條目):[Item 21: Design interfaces for posterity(為后代設計接口)](/Chapter-4/Chapter-4-Item-21-Design-interfaces-for-posterity.md)**
                  <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>

                              哎呀哎呀视频在线观看