<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之旅 廣告
                ## Chapter 3. Methods Common to All Objects(對象的通用方法) ### Item 13: Override clone judiciously(明智地覆蓋 clone 方法) The Cloneable interface was intended as a mixin interface (Item 20) for classes to advertise that they permit cloning. Unfortunately, it fails to serve this purpose. Its primary flaw is that it lacks a clone method, and Object’s clone method is protected. You cannot, without resorting to reflection (Item 65), invoke clone on an object merely because it implements Cloneable. Even a reflective invocation may fail, because there is no guarantee that the object has an accessible clone method. Despite this flaw and many others, the facility is in reasonably wide use, so it pays to understand it. This item tells you how to implement a well-behaved clone method, discusses when it is appropriate to do so, and presents alternatives. Cloneable 接口的目的是作為 mixin 接口([Item-20](/Chapter-4/Chapter-4-Item-20-Prefer-interfaces-to-abstract-classes.md)),用于讓類來宣稱它們允許克隆。不幸的是,它沒有達到這個目的。它的主要缺點是缺少 clone 方法,并且 Object 類的 clone 方法是受保護的。如果不求助于反射([Item-65](/Chapter-9/Chapter-9-Item-65-Prefer-interfaces-to-reflection.md)),就不能僅僅因為對象實現了 Cloneable 接口就能調用 clone 方法。即使反射調用也可能失敗,因為不能保證對象具有可訪問的 clone 方法。盡管存在多種缺陷,但該機制的使用范圍相當廣泛,因此理解它是值得的。本條目將告訴你如何實現行為良好的 clone 方法,討論什么時候應該這樣做,并提供替代方案。 **譯注:mixin 接口很可能是指一種帶有全部實現或者部分實現的接口,其主要作用是:(1)更好的進行代碼復用;(2)間接實現多重繼承;(3)擴展功能。與傳統接口相比,傳統接口中不帶實現,而 mixin 接口帶有實現。** So what does Cloneable do, given that it contains no methods? It determines the behavior of Object’s protected clone implementation: if a class implements Cloneable, Object’s clone method returns a field-byfield copy of the object; otherwise it throws CloneNotSupportedException. This is a highly atypical use of interfaces and not one to be emulated. Normally, implementing an interface says something about what a class can do for its clients. In this case, it modifies the behavior of a protected method on a superclass. 既然 Cloneable 接口不包含任何方法,用它來做什么呢?它決定了 Object 類受保護的 clone 實現的行為:如果一個類實現了 Cloneable 接口,Object 類的 clone 方法則返回該類實例的逐字段拷貝;否則它會拋出 CloneNotSupportedException。這是接口非常不典型的一種使用方式,不應該效仿。通常,類實現接口可以表明類能夠為其客戶端做些什么。在本例中,它修改了超類上受保護的方法的行為。 Though the specification doesn’t say it, in practice, a class implementing Cloneable is expected to provide a properly functioning public clone method. In order to achieve this, the class and all of its superclasses must obey a complex, unenforceable, thinly documented protocol. The resulting mechanism is fragile, dangerous, and extralinguistic: it creates objects without calling a constructor. 雖然規范沒有說明,但是在實踐中,實現 Cloneable 接口的類應該提供一個功能正常的公共 clone 方法。為了實現這一點,類及其所有超類必須遵守復雜的、不可強制執行的、文檔很少的協議。產生的機制是脆弱的、危險的和非語言的:即它創建對象而不調用構造函數。 The general contract for the clone method is weak. Here it is, copied from the Object specification: clone 方法的一般約定很薄弱。下面的內容是從 Object 規范復制過來的: --- Creates and returns a copy of this object. The precise meaning of “copy” may depend on the class of the object. The general intent is that, for any object x,the expression ``` x.clone() != x ``` will be true, and the expression ``` x.clone().getClass() == x.getClass() ``` will be true, but these are not absolute requirements. While it is typically the case that ``` x.clone().equals(x) ``` will be true, this is not an absolute requirement. --- clone 方法創建并返回對象的副本。「副本」的確切含義可能取決于對象的類別。通常,對于任何對象 x,表達式 `x.clone() != x`、`x.clone().getClass() == x.getClass()` 以及 `x.clone().equals(x)` 的值都將為 true,但都不是絕對的。 **譯注:以上情況的 equals 方法應覆蓋默認實現,改為比較對象中的字段才能得到 true。默認實現是比較兩個引用類型的內存地址,結果必然為 false** By convention, the object returned by this method should be obtained by calling super.clone. If a class and all of its superclasses (except Object) obey this convention, it will be the case that ``` x.clone().getClass() == x.getClass(). ``` 按照約定,clone 方法返回的對象應該通過調用 super.clone() 來獲得。如果一個類和它的所有超類(Object 類除外)都遵守這個約定,在這種情況下,表達式 `x.clone().getClass() == x.getClass()` 則為 true By convention, the returned object should be independent of the object being cloned. To achieve this independence, it may be necessary to modify one or more fields of the object returned by super.clone before returning it. 按照約定,返回的對象應該獨立于被克隆的對象。為了實現這種獨立性,可能需要在 super.clone() 返回前,修改對象的一個或多個字段。 This mechanism is vaguely similar to constructor chaining, except that it isn’t enforced: if a class’s clone method returns an instance that is not obtained by calling super.clone but by calling a constructor, the compiler won’t complain, but if a subclass of that class calls super.clone, the resulting object will have the wrong class, preventing the subclass from clone method from working properly. If a class that overrides clone is final, this convention may be safely ignored, as there are no subclasses to worry about. But if a final class has a clone method that does not invoke super.clone, there is no reason for the class to implement Cloneable, as it doesn’t rely on the behavior of Object’s clone implementation. 這種機制有點類似于構造方法鏈,只是沒有強制執行: - (1)如果一個類的 clone 方法返回的實例不是通過調用 super.clone() 而是通過調用構造函數獲得的,編譯器不會報錯,但是如果這個類的一個子類調用 super.clone(),由此產生的對象類型將是錯誤的,影響子類 clone 方法正常工作。 - (2)如果覆蓋 clone 方法的類是 final 修飾的,那么可以安全地忽略這個約定,因為沒有子類需要擔心。 - (3)如果一個 final 修飾的類不調用 super.clone() 的 clone 方法。類沒有理由實現 Cloneable 接口,因為它不依賴于 Object 類的 clone 實現的行為。 **譯注:本段描述(1)的例子如下,表達式 `x.clone().getClass() == x.getClass()` 值為 false** ``` class Base { @Override protected Object clone() throws CloneNotSupportedException { return new Base(); // ① } } class BasePro extends Base implements Cloneable { @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public static void main(String[] args) throws Exception { BasePro basePro = new BasePro(); System.out.println(basePro.clone().getClass()); // 輸出 class com.example.demo.Base System.out.println(basePro.getClass()); // 輸出 class com.example.demo.BasePro } } ``` 可采用兩種方式修復 - ① 處改用 super.clone() - 移除 Base 類整個 clone() 實現 Suppose you want to implement Cloneable in a class whose superclass provides a well-behaved clone method. First call super.clone. The object you get back will be a fully functional replica of the original. Any fields declared in your class will have values identical to those of the original. If every field contains a primitive value or a reference to an immutable object, the returned object may be exactly what you need, in which case no further processing is necessary. This is the case, for example, for the PhoneNumber class in Item 11, but note that **immutable classes should never provide a clone method** because it would merely encourage wasteful copying. With that caveat, here’s how a clone method for PhoneNumber would look: 假設你希望在一個類中實現 Cloneable 接口,該類的超類提供了一個表現良好的 clone 方法。首先調用 super.clone()。返回的對象將是原始對象的完整功能副本。類中聲明的任何字段都具有與原始字段相同的值。如果每個字段都包含一個基本類型或對不可變對象的引用,那么返回的對象可能正是你所需要的,在這種情況下不需要進一步的處理。例如,對于[Item-11](/Chapter-3/Chapter-3-Item-11-Always-override-hashCode-when-you-override-equals.md)中的 PhoneNumber 類就是這樣,但是要注意,**不可變類永遠不應該提供 clone 方法**,because it would merely encourage wasteful copying. 有了這個警告,以下是 PhoneNumber 類的 clone 方法概貌: ``` // Clone method for class with no references to mutable state @Override public PhoneNumber clone() { try { return (PhoneNumber) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(); // Can't happen } } ``` In order for this method to work, the class declaration for PhoneNumber would have to be modified to indicate that it implements Cloneable. Though Object’s clone method returns Object, this clone method returns PhoneNumber. It is legal and desirable to do this because Java supports covariant return types. In other words, an overriding method’s return type can be a subclass of the overridden method’s return type. This eliminates the need for casting in the client. We must cast the result of super.clone from Object to PhoneNumber before returning it, but the cast is guaranteed to succeed. 為了讓這個方法工作,必須修改 PhoneNumber 類的聲明,使之實現 Cloneable 接口。雖然 Object 的 clone 方法返回 Object 類型,但是這個 clone 方法返回 PhoneNumber 類型。這樣做是合法的,也是可取的,因為 Java 的返回值類型支持協變。換句話說,覆蓋方法的返回類型可以是被覆蓋方法的返回類型的子類。這樣就不需要在客戶端中進行強制轉換。我們必須把源自 Object 類的 super.clone() 方法在返回前將結果轉換為 PhoneNumber 類型,這類強制轉換肯定會成功。 The call to super.clone is contained in a try-catch block. This is because Object declares its clone method to throw CloneNotSupportedException, which is a checked exception. Because PhoneNumber implements Cloneable, we know the call to super.clone will succeed. The need for this boilerplate indicates that CloneNotSupportedException should have been unchecked (Item 71). 將 super.clone() 包含在 try-catch 塊中。這是因為 Object 類聲明的 clone 方法會拋出 CloneNotSupportedException,這是一種 checked exception。因為 PhoneNumber 類實現了 Cloneable 接口,所以我們知道對 super.clone() 的調用將會成功。這個樣板文件的需求表明 CloneNotSupportedException 應該是 unchecked exception([Item-71](/Chapter-10/Chapter-10-Item-71-Avoid-unnecessary-use-of-checked-exceptions.md))。 If an object contains fields that refer to mutable objects, the simple clone implementation shown earlier can be disastrous. For example, consider the Stack class in Item 7: 如果對象的字段包含可變對象的引用,前面所示 clone 方法的這種簡易實現可能引發災難。例如,考慮 [Item-7](/Chapter-2/Chapter-2-Item-7-Eliminate-obsolete-object-references.md) 中的 Stack 類: ``` public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { this.elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result; } // Ensure space for at least one more element. private void ensureCapacity() { if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); } } ``` Suppose you want to make this class cloneable. If the clone method merely returns super.clone(), the resulting Stack instance will have the correct value in its size field, but its elements field will refer to the same array as the original Stack instance. Modifying the original will destroy the invariants in the clone and vice versa. You will quickly find that your program produces nonsensical results or throws a NullPointerException. 假設你想讓這個類可克隆。如果 clone 方法只返回 super.clone(),得到的 Stack 實例在其 size 字段中會有正確的值,但其 elements 字段將引用與原始 Stack 實例相同的數組。修改初始值將破壞克隆的不變性,反之亦然。你將很快發現你的程序產生了無意義的結果或拋出 NullPointerException。 This situation could never occur as a result of calling the sole constructor in the Stack class. In effect, the clone method functions as a constructor; you must ensure that it does no harm to the original object and that it properly establishes invariants on the clone. In order for the clone method on Stack to work properly, it must copy the internals of the stack. The easiest way to do this is to call clone recursively on the elements array: 調用 Stack 類中唯一構造函數的情況永遠不會發生。實際上,clone 方法將充當構造函數;你必須確保它不會對原始對象造成傷害,并且 clone 方法正確地實現了不變性。為了使 Stack 類上的 clone 方法正常工作,它必須復制 Stack 類實例的內部。最簡單的做法是在 elements 字段對應的數組遞歸調用 clone 方法: ``` // Clone method for class with references to mutable state @Override public Stack clone() { try { Stack result = (Stack) super.clone(); result.elements = elements.clone(); return result; } catch (CloneNotSupportedException e) { throw new AssertionError(); } } ``` Note that we do not have to cast the result of elements.clone to Object[]. Calling clone on an array returns an array whose runtime and compile-time types are identical to those of the array being cloned. This is the preferred idiom to duplicate an array. In fact, arrays are the sole compelling use of the clone facility. 注意,我們不需要將 `elements.clone` 的結果強制轉換到 `Object[]`。在數組上調用 clone 方法將返回一個數組,該數組的運行時和編譯時類型與被克隆的數組相同。這是復制數組的首選習慣用法。實際上,復制數組是 clone 機制唯一令人信服的使用場景。 Note also that the earlier solution would not work if the elements field were final because clone would be prohibited from assigning a new value to the field. This is a fundamental problem: like serialization, the Cloneable architecture is incompatible with normal use of final fields referring to mutable objects, except in cases where the mutable objects may be safely shared between an object and its clone. In order to make a class cloneable, it may be necessary to remove final modifiers from some fields. 還要注意,如果 elements 字段是 final 修飾的,上述解決方案就無法工作,因為 clone 方法將被禁止為字段分配新值。這是一個基礎問題:與序列化一樣,可克隆體系結構與使用 final 修飾可變對象引用的常用方式不兼容,除非在對象與其克隆對象之間可以安全地共享可變對象。為了使類可克隆,可能需要從某些字段中刪除 final 修飾符。 It is not always sufficient merely to call clone recursively. For example,suppose you are writing a clone method for a hash table whose internals consist of an array of buckets, each of which references the first entry in a linked list of key-value pairs. For performance, the class implements its own lightweight singly linked list instead of using java.util.LinkedList internally: 僅僅遞歸調用 clone 方法并不總是足夠的。例如,假設你正在為 HashTable 編寫一個 clone 方法,HashTable 的內部由一組 bucket 組成,每個 bucket 引用鍵-值對鏈表中的第一個條目。為了提高性能,類實現了自己的輕量級單鏈表,而不是在內部使用 `java.util.LinkedList`: ``` public class HashTable implements Cloneable { private Entry[] buckets = ...; private static class Entry { final Object key; Object value; Entry next; Entry(Object key, Object value, Entry next) { this.key = key; this.value = value; this.next = next; } } ... // Remainder omitted } ``` Suppose you merely clone the bucket array recursively, as we did for Stack: 假設你只是像對 Stack 所做的那樣,遞歸克隆 bucket 數組,如下所示: ``` // Broken clone method - results in shared mutable state! @Override public HashTable clone() { try { HashTable result = (HashTable) super.clone(); result.buckets = buckets.clone(); return result; } catch (CloneNotSupportedException e) { throw new AssertionError(); } } ``` Though the clone has its own bucket array, this array references the same linked lists as the original, which can easily cause nondeterministic behavior in both the clone and the original. To fix this problem, you’ll have to copy the linked list that comprises each bucket. Here is one common approach: 盡管 clone 方法有自己的 bucket 數組,但該數組引用的鏈接列表與原始鏈表相同,這很容易導致克隆和原始的不確定性行為。要解決這個問題,你必須復制包含每個 bucket 的鏈表。這里有一個常見的方法: ``` // Recursive clone method for class with complex mutable state public class HashTable implements Cloneable { private Entry[] buckets = ...; private static class Entry { final Object key; Object value; Entry next; Entry(Object key, Object value, Entry next) { this.key = key; this.value = value; this.next = next; } // Recursively copy the linked list headed by this Entry Entry deepCopy() { return new Entry(key, value,next == null ? null : next.deepCopy()); } } @Override public HashTable clone() { try { HashTable result = (HashTable) super.clone(); result.buckets = new Entry[buckets.length]; for (int i = 0; i < buckets.length; i++) if (buckets[i] != null) result.buckets[i] = buckets[i].deepCopy(); return result; } catch (CloneNotSupportedException e) { throw new AssertionError(); } } ... // Remainder omitted } ``` The private class HashTable.Entry has been augmented to support a “deep copy” method. The clone method on HashTable allocates a new buckets array of the proper size and iterates over the original buckets array,deep-copying each nonempty bucket. The deepCopy method on Entry invokes itself recursively to copy the entire linked list headed by the entry. While this technique is cute and works fine if the buckets aren’t too long, it is not a good way to clone a linked list because it consumes one stack frame for each element in the list. If the list is long, this could easily cause a stack overflow. To prevent this from happening, you can replace the recursion in deepCopy with iteration: 私有內部類 HashTable.Entry 已經被增強,它提供了進行「深拷貝」的方法。HashTable 上的 clone 方法分配一個大小合適的新 buckets 數組,并遍歷原始 buckets 數組,對每個非空 buckets 元素進行深拷貝。Entry 類的 deepCopy() 方法會被遞歸調用直至復制完整個鏈表(該鏈表以 Entry 類的實例作為頭節點)。這種方法雖然很靈活,而且在 buckets 不太長的情況下可以很好地工作,但是克隆鏈表并不是一個好方法,因為它為鏈表中的每個元素消耗一個堆棧幀。如果列表很長,很容易導致堆棧溢出。為了防止這種情況的發生,你可以用迭代替換 deepCopy() 方法的遞歸調用: ``` // Iteratively copy the linked list headed by this Entry Entry deepCopy() { Entry result = new Entry(key, value, next); for (Entry p = result; p.next != null; p = p.next) p.next = new Entry(p.next.key, p.next.value, p.next.next); return result; } ``` A final approach to cloning complex mutable objects is to call super.clone, set all of the fields in the resulting object to their initial state,and then call higher-level methods to regenerate the state of the original object. In the case of our HashTable example, the buckets field would be initialized to a new bucket array, and the put(key, value) method (not shown) would be invoked for each key-value mapping in the hash table being cloned. This approach typically yields a simple, reasonably elegant clone method that does not run as quickly as one that directly manipulates the innards of the clone. While this approach is clean, it is antithetical to the whole Cloneable architecture because it blindly overwrites the field-by-field object copy that forms the basis of the architecture. 克隆復雜可變對象的最后一種方法是調用 super.clone(),將結果對象中的所有字段設置為初始狀態,然后調用更高級別的方法重新生成原始對象的狀態。在我們的 HashTable 示例中,buckets 字段將初始化為一個新的 bucket 數組,并且對于克隆的 hash 表中的每個鍵值映射將調用 put(key, value) 方法(未顯示)。這種方法通常產生一個簡單、相當優雅的 clone 方法,它的運行速度不如直接操作克隆的內部的方法快。雖然這種方法很簡潔,但它與整個可克隆體系結構是對立的,因為它盲目地覆蓋了構成體系結構基礎的逐字段對象副本。 Like a constructor, a clone method must never invoke an overridable method on the clone under construction (Item 19). If clone invokes a method that is overridden in a subclass, this method will execute before the subclass has had a chance to fix its state in the clone, quite possibly leading to corruption in the clone and the original. Therefore, the put(key, value) method discussed in the previous paragraph should be either final or private. (If it is private, it is presumably the “helper method” for a nonfinal public method.) 與構造函數一樣,clone 方法絕不能在正在構建的克隆上調用可覆蓋方法([Item-19](/Chapter-4/Chapter-4-Item-19-Design-and-document-for-inheritance-or-else-prohibit-it.md))。如果 clone 調用一個在子類中被重寫的方法,這個方法將在子類有機會修復其在克隆中的狀態之前執行,很可能導致克隆和原始的破壞。因此,前一段中討論的 put(key, value) 方法應該是 final 修飾或 private 修飾的方法。(如果它是私有的,那么它可能是沒有 final 修飾的公共「助手方法」。) Object’s clone method is declared to throw CloneNotSupportedException, but overriding methods need not. **Public clone methods should omit the throws clause,** as methods that don’t throw checked exceptions are easier to use (Item 71). 對象的 clone 方法被聲明為拋出 CloneNotSupportedException,但是重寫方法不需要。**公共克隆方法應該省略 throw 子句,** 作為不拋出受控異常的方法更容易使用([Item-71](/Chapter-10/Chapter-10-Item-71-Avoid-unnecessary-use-of-checked-exceptions.md))。 You have two choices when designing a class for inheritance (Item 19), but whichever one you choose, the class should not implement Cloneable. You may choose to mimic the behavior of Object by implementing a properly functioning protected clone method that is declared to throw CloneNotSupportedException. This gives subclasses the freedom to implement Cloneable or not, just as if they extended Object directly.Alternatively, you may choose not to implement a working clone method, and to prevent subclasses from implementing one, by providing the following degenerate clone implementation: 用繼承([Item-19](/Chapter-4/Chapter-4-Item-19-Design-and-document-for-inheritance-or-else-prohibit-it.md))方式設計一個類時,你有兩種選擇,但是無論你選擇哪一種,都不應該實現 Cloneable 接口。你可以選擇通過實現一個功能正常的受保護克隆方法來模擬 Object 的行為,該方法聲明為拋出 CloneNotSupportedException。這給子類實現 Cloneable 或不實現 Cloneable 的自由,就像它們直接擴展對象一樣。或者,你可以選擇不實現一個有效的克隆方法,并通過提供以下退化的克隆實現來防止子類實現它: ``` // clone method for extendable class not supporting Cloneable @Override protected final Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } ``` There is one more detail that bears noting. If you write a thread-safe class that implements Cloneable, remember that its clone method must be properly synchronized, just like any other method (Item 78). Object’s clone method is not synchronized, so even if its implementation is otherwise satisfactory, you may have to write a synchronized clone method that returns super.clone(). 還有一個細節需要注意。如果你編寫了一個實現了 Cloneable 接口的線程安全類,請記住它的 clone 方法必須正確同步,就像其他任何方法一樣([Item-78](/Chapter-11/Chapter-11-Item-78-Synchronize-access-to-shared-mutable-data.md))。Object 類的 clone 方法不是同步的,因此即使它的實現在其他方面是令人滿意的,你也可能需要編寫一個返回 super.clone() 的同步 clone 方法。 To recap, all classes that implement Cloneable should override clone with a public method whose return type is the class itself. This method should first call super.clone, then fix any fields that need fixing. Typically, this means copying any mutable objects that comprise the internal “deep structure” of the object and replacing the clone’s references to these objects with references to their copies. While these internal copies can usually be made by calling clone recursively, this is not always the best approach. If the class contains only primitive fields or references to immutable objects, then it is likely the case that no fields need to be fixed. There are exceptions to this rule. For example, a field representing a serial number or other unique ID will need to be fixed even if it is primitive or immutable. 回顧一下,所有實現 Cloneable 接口的類都應該使用一個返回類型為類本身的公共方法覆蓋 clone。這個方法應該首先調用 super.clone(),然后「修復」任何需要「修復」的字段。通常,這意味著復制任何包含對象內部「深層結構」的可變對象,并將克隆對象對這些對象的引用替換為對其副本的引用。雖然這些內部副本通常可以通過遞歸調用 clone 來實現,但這并不總是最好的方法。如果類只包含基本數據類型的字段或對不可變對象的引用,那么很可能不需要修復任何字段。這條規則也有例外。例如,表示序列號或其他唯一 ID 的字段需要修復,即使它是基本數據類型或不可變的。 Is all this complexity really necessary? Rarely. If you extend a class that already implements Cloneable, you have little choice but to implement a well-behaved clone method. Otherwise, you are usually better off providing an alternative means of object copying. A better approach to object copying is to provide a copy constructor or copy factory. A copy constructor is simply a constructor that takes a single argument whose type is the class containing the constructor, for example, 搞這么復雜真的有必要嗎?答案是否定的。如果你擴展了一個已經實現了 Cloneable 接口的類,那么除了實現行為良好的 clone 方法之外,你別無選擇。否則,最好提供對象復制的替代方法。一個更好的對象復制方法是提供一個復制構造函數或復制工廠。復制構造函數是一個簡單的構造函數,它接受單個參數,其類型是包含構造函數的類,例如 ``` // Copy constructor public Yum(Yum yum) { ... }; ``` A copy factory is the static factory (Item 1) analogue of a copy constructor: 復制工廠與復制構造函數的靜態工廠([Item-1](/Chapter-2/Chapter-2-Item-1-Consider-static-factory-methods-instead-of-constructors.md))類似: ``` // Copy factory public static Yum newInstance(Yum yum) { ... }; ``` The copy constructor approach and its static factory variant have many advantages over Cloneable/clone: they don’t rely on a risk-prone extralinguistic object creation mechanism; they don’t demand unenforceable adherence to thinly documented conventions; they don’t conflict with the proper use of final fields; they don’t throw unnecessary checked exceptions; and they don’t require casts. 復制構造函數方法及其靜態工廠變體與克隆/克隆相比有許多優點:它們不依賴于易發生風險的語言外對象創建機制;他們不要求無法強制執行的約定;它們與最終字段的正確使用不沖突;它們不會拋出不必要的檢查異常;而且不需要強制類型轉換。 Furthermore, a copy constructor or factory can take an argument whose type is an interface implemented by the class. For example, by convention all generalpurpose collection implementations provide a constructor whose argument is of type Collection or Map. Interface-based copy constructors and factories,more properly known as conversion constructors and conversion factories, allow the client to choose the implementation type of the copy rather than forcing the client to accept the implementation type of the original. For example, suppose you have a HashSet, s, and you want to copy it as a TreeSet. The clone method can’t offer this functionality, but it’s easy with a conversion constructor:new TreeSet<>(s). 此外,復制構造函數或工廠可以接受類型為類實現的接口的參數。例如,按照約定,所有通用集合實現都提供一個構造函數,其參數為 collection 或 Map 類型。基于接口的復制構造函數和工廠(更確切地稱為轉換構造函數和轉換工廠)允許客戶端選擇副本的實現類型,而不是強迫客戶端接受原始的實現類型。例如,假設你有一個 HashSet s,并且希望將它復制為 TreeSet。克隆方法不能提供這種功能,但是使用轉換構造函數很容易:new TreeSet<>(s)。 Given all the problems associated with Cloneable, new interfaces should not extend it, and new extendable classes should not implement it. While it’s less harmful for final classes to implement Cloneable, this should be viewed as a performance optimization, reserved for the rare cases where it is justified (Item 67). As a rule, copy functionality is best provided by constructors or factories. A notable exception to this rule is arrays, which are best copied with the clone method. 考慮到與 Cloneable 相關的所有問題,新的接口不應該擴展它,新的可擴展類不應該實現它。雖然 final 類實現 Cloneable 接口的危害要小一些,但這應該被視為一種性能優化,僅在極少數情況下([Item-67](/Chapter-9/Chapter-9-Item-67-Optimize-judiciously.md))是合理的。通常,復制功能最好由構造函數或工廠提供。這個規則的一個明顯的例外是數組,最好使用 clone 方法來復制數組。 --- **[Back to contents of the chapter(返回章節目錄)](/Chapter-3/Chapter-3-Introduction.md)** - **Previous Item(上一條目):[Item 12: Always override toString(始終覆蓋 toString 方法)](/Chapter-3/Chapter-3-Item-12-Always-override-toString.md)** - **Next Item(下一條目):[Item 14: Consider implementing Comparable(考慮實現 Comparable 接口)](/Chapter-3/Chapter-3-Item-14-Consider-implementing-Comparable.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>

                              哎呀哎呀视频在线观看