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

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## Chapter 12. Serialization(序列化) ### Item 86: Implement Serializable with great caution(非常謹慎地實現 Serializable) Allowing a class’s instances to be serialized can be as simple as adding the words implements Serializable to its declaration. Because this is so easy to do, there was a common misconception that serialization requires little effort on the part of the programmer. The truth is far more complex. While the immediate cost to make a class serializable can be negligible, the long-term costs are often substantial. 使類的實例可序列化非常簡單,只需實現 Serializable 接口即可。因為這很容易做到,所以有一個普遍的誤解,認為序列化只需要程序員付出很少的努力。而事實上要復雜得多。雖然使類可序列化的即時代價可以忽略不計,但長期代價通常是巨大的。 **A major cost of implementing Serializable is that it decreases the flexibility to change a class’s implementation once it has been released.** When a class implements Serializable, its byte-stream encoding (or serialized form) becomes part of its exported API. Once you distribute a class widely, you are generally required to support the serialized form forever, just as you are required to support all other parts of the exported API. If you do not make the effort to design a custom serialized form but merely accept the default, the serialized form will forever be tied to the class’s original internal representation. In other words, if you accept the default serialized form, the class’s private and package-private instance fields become part of its exported API, and the practice of minimizing access to fields (Item 15) loses its effectiveness as a tool for information hiding. **實現 Serializable 接口的一個主要代價是,一旦類的實現被發布,它就會降低更改該類實現的靈活性。** 當類實現 Serializable 時,其字節流編碼(或序列化形式)成為其導出 API 的一部分。一旦廣泛分發了一個類,通常就需要永遠支持序列化的形式,就像需要支持導出 API 的所有其他部分一樣。如果你不努力設計自定義序列化形式,而只是接受默認形式,則序列化形式將永遠綁定在類的原始內部實現上。換句話說,如果你接受默認的序列化形式,類中私有的包以及私有實例字段將成為其導出 API 的一部分,此時最小化字段作用域([Item-15](/Chapter-4/Chapter-4-Item-15-Minimize-the-accessibility-of-classes-and-members.md))作為信息隱藏的工具,將失去其有效性。 If you accept the default serialized form and later change a class’s internal representation, an incompatible change in the serialized form will result. Clients attempting to serialize an instance using an old version of the class and deserialize it using the new one (or vice versa) will experience program failures. It is possible to change the internal representation while maintaining the original serialized form (using ObjectOutputStream.putFields and ObjectInputStream.readFields), but it can be difficult and leaves visible warts in the source code. If you opt to make a class serializable, you should carefully design a high-quality serialized form that you’re willing to live with for the long haul (Items 87, 90). Doing so will add to the initial cost of development, but it’s worth the effort. Even a well-designed serialized form places constraints on the evolution of a class; an ill-designed serialized form can be crippling. 如果你接受默認的序列化形式,然后更改了類的內部實現,則會導致與序列化形式不兼容。試圖使用類的舊版本序列化實例,再使用新版本反序列化實例的客戶端(反之亦然)程序將會失敗。當然,可以在維護原始序列化形式的同時更改內部實現(使用 ObjectOutputStream.putFields 或 ObjectInputStream.readFields),但這可能會很困難,并在源代碼中留下明顯的缺陷。如果你選擇使類可序列化,你應該仔細設計一個高質量的序列化形式,以便長期使用([Item-87](/Chapter-12/Chapter-12-Item-87-Consider-using-a-custom-serialized-form.md)、[Item-90](/Chapter-12/Chapter-12-Item-90-Consider-serialization-proxies-instead-of-serialized-instances.md))。這樣做會增加開發的初始成本,但是這樣做是值得的。即使是設計良好的序列化形式,也會限制類的演化;而設計不良的序列化形式,則可能會造成嚴重后果。 A simple example of the constraints on evolution imposed by serializability concerns stream unique identifiers, more commonly known as serial version UIDs. Every serializable class has a unique identification number associated with it. If you do not specify this number by declaring a static final long field named serialVersionUID, the system automatically generates it at runtime by applying a cryptographic hash function (SHA-1) to the structure of the class. This value is affected by the names of the class, the interfaces it implements, and most of its members, including synthetic members generated by the compiler. If you change any of these things, for example, by adding a convenience method, the generated serial version UID changes. If you fail to declare a serial version UID, compatibility will be broken, resulting in an InvalidClassException at runtime. 可序列化會使類的演變受到限制,施加這種約束的一個簡單示例涉及流的唯一標識符,通常稱其為串行版本 UID。每個可序列化的類都有一個與之關聯的唯一標識符。如果你沒有通過聲明一個名為 serialVersionUID 的靜態 final long 字段來指定這個標識符,那么系統將在運行時對類應用加密散列函數(SHA-1)自動生成它。這個值受到類的名稱、實現的接口及其大多數成員(包括編譯器生成的合成成員)的影響。如果你更改了其中任何一項,例如,通過添加一個臨時的方法,生成的序列版本 UID 就會更改。如果你未能聲明序列版本 UID,兼容性將被破壞,從而在運行時導致 InvalidClassException。 **A second cost of implementing Serializable is that it increases the likelihood of bugs and security holes (Item 85).** Normally, objects are created with constructors; serialization is an extralinguistic mechanism for creating objects. Whether you accept the default behavior or override it, deserialization is a “hidden constructor” with all of the same issues as other constructors. Because there is no explicit constructor associated with deserialization, it is easy to forget that you must ensure that it guarantees all of the invariants established by the constructors and that it does not allow an attacker to gain access to the internals of the object under construction. Relying on the default deserialization mechanism can easily leave objects open to invariant corruption and illegal access (Item 88). **實現 Serializable 接口的第二個代價是,增加了出現 bug 和安全漏洞的可能性(第85項)。** 通常,對象是用構造函數創建的;序列化是一種用于創建對象的超語言機制。無論你接受默認行為還是無視它,反序列化都是一個「隱藏構造函數」,其他構造函數具有的所有問題它都有。由于沒有與反序列化關聯的顯式構造函數,因此很容易忘記必須讓它能夠保證所有的不變量都是由構造函數建立的,并且不允許攻擊者訪問正在構造的對象內部。依賴于默認的反序列化機制,會讓對象輕易地遭受不變性破壞和非法訪問([Item-88](/Chapter-12/Chapter-12-Item-88-Write-readObject-methods-defensively.md))。 **A third cost of implementing Serializable is that it increases the testing burden associated with releasing a new version of a class.** When a serializable class is revised, it is important to check that it is possible to serialize an instance in the new release and deserialize it in old releases, and vice versa. The amount of testing required is thus proportional to the product of the number of serializable classes and the number of releases, which can be large. You must ensure both that the serialization-deserialization process succeeds and that it results in a faithful replica of the original object. The need for testing is reduced if a custom serialized form is carefully designed when the class is first written (Items 87, 90). **實現 Serializable 接口的第三個代價是,它增加了與發布類的新版本相關的測試負擔。** 當一個可序列化的類被修改時,重要的是檢查是否可以在新版本中序列化一個實例,并在舊版本中反序列化它,反之亦然。因此,所需的測試量與可序列化類的數量及版本的數量成正比,工作量可能很大。你必須確保「序列化-反序列化」過程成功,并確保它生成原始對象的無差錯副本。如果在第一次編寫類時精心設計了自定義序列化形式,那么測試的工作量就會減少([Item-87](/Chapter-12/Chapter-12-Item-87-Consider-using-a-custom-serialized-form.md)、[Item-90](/Chapter-12/Chapter-12-Item-90-Consider-serialization-proxies-instead-of-serialized-instances.md))。 **Implementing Serializable is not a decision to be undertaken lightly.** It is essential if a class is to participate in a framework that relies on Java serialization for object transmission or persistence. Also, it greatly eases the use of a class as a component in another class that must implement Serializable. There are, however, many costs associated with implementing Serializable. Each time you design a class, weigh the costs against the benefits. Historically, value classes such as BigInteger and Instant implemented Serializable, and collection classes did too. Classes representing active entities, such as thread pools, should rarely implement Serializable. **實現 Serializable 接口并不是一個輕松的決定。** 如果一個類要參與一個框架,該框架依賴于 Java 序列化來進行對象傳輸或持久化,這對于類來說實現 Serializable 接口就是非常重要的。此外,如果類 A 要成為另一個類 B 的一個組件,類 B 必須實現 Serializable 接口,若類 A 可序列化,它就會更易于被使用。然而,與實現 Serializable 相關的代價很多。每次設計一個類時,都要權衡利弊。歷史上,像 BigInteger 和 Instant 這樣的值類實現了 Serializable 接口,集合類也實現了 Serializable 接口。表示活動實體(如線程池)的類很少情況適合實現 Serializable 接口。 **Classes designed for inheritance (Item 19) should rarely implement Serializable, and interfaces should rarely extend it.** Violating this rule places a substantial burden on anyone who extends the class or implements the interface. There are times when it is appropriate to violate the rule. For example, if a class or interface exists primarily to participate in a framework that requires all participants to implement Serializable, then it may make sense for the class or interface to implement or extend Serializable. **為繼承而設計的類([Item-19](/Chapter-4/Chapter-4-Item-19-Design-and-document-for-inheritance-or-else-prohibit-it.md))很少情況適合實現 Serializable 接口,接口也很少情況適合擴展它。** 違反此規則會給擴展類或實現接口的任何人帶來很大的負擔。有時,違反規則是恰當的。例如,如果一個類或接口的存在主要是為了參與一個要求所有參與者都實現 Serializable 接口的框架,那么類或接口實現或擴展 Serializable 可能是有意義的。 Classes designed for inheritance that do implement Serializable include Throwable and Component. Throwable implements Serializable so RMI can send exceptions from server to client. Component implements Serializable so GUIs can be sent, saved, and restored, but even in the heyday of Swing and AWT, this facility was little-used in practice. 在為了繼承而設計的類中,Throwable 類和 Component 類都實現了 Serializable 接口。正是因為 Throwable 實現了 Serializable 接口,RMI 可以將異常從服務器發送到客戶端;Component 類實現了 Serializable 接口,因此可以發送、保存和恢復 GUI,但即使在 Swing 和 AWT 的鼎盛時期,這個工具在實踐中也很少使用。 If you implement a class with instance fields that is both serializable and extendable, there are several risks to be aware of. If there are any invariants on the instance field values, it is critical to prevent subclasses from overriding the finalize method, which the class can do by overriding finalize and declaring it final. Otherwise, the class will be susceptible to finalizer attacks (Item 8). Finally, if the class has invariants that would be violated if its instance fields were initialized to their default values (zero for integral types, false for boolean, and null for object reference types), you must add this readObjectNoData method: 如果你實現了一個帶有實例字段的類,它同時是可序列化和可擴展的,那么需要注意幾個風險。如果實例字段值上有任何不變量,關鍵是要防止子類覆蓋 finalize 方法,可以通過覆蓋 finalize 并聲明它為 final 來做到。最后,如果類的實例字段初始化為默認值(整數類型為 0,布爾值為 false,對象引用類型為 null),那么必須添加 readObjectNoData 方法: ``` // readObjectNoData for stateful extendable serializable classes private void readObjectNoData() throws InvalidObjectException { throw new InvalidObjectException("Stream data required"); } ``` This method was added in Java 4 to cover a corner case involving the addition of a serializable superclass to an existing serializable class [Serialization, 3.5]. 這個方法是在 Java 4 中添加的,涉及將可序列化超類添加到現有可序列化類 [Serialization, 3.5] 的特殊情況。 There is one caveat regarding the decision not to implement Serializable. If a class designed for inheritance is not serializable, it may require extra effort to write a serializable subclass. Normal deserialization of such a class requires the superclass to have an accessible parameterless constructor [Serialization, 1.10]. If you don’t provide such a constructor, subclasses are forced to use the serialization proxy pattern (Item 90). 關于不實現 Serializable 的決定,有一個警告。如果為繼承而設計的類不可序列化,則可能需要額外的工作來編寫可序列化的子類。子類的常規反序列化,要求超類具有可訪問的無參數構造函數 [Serialization, 1.10]。如果不提供這樣的構造函數,子類將被迫使用序列化代理模式([Item-90](/Chapter-12/Chapter-12-Item-90-Consider-serialization-proxies-instead-of-serialized-instances.md))。 **Inner classes (Item 24) should not implement Serializable.** They use compiler-generated synthetic fields to store references to enclosing instances and to store values of local variables from enclosing scopes. How these fields correspond to the class definition is unspecified, as are the names of anonymous and local classes. Therefore, the default serialized form of an inner class is illdefined. A static member class can, however, implement Serializable. **內部類([Item-24](/Chapter-4/Chapter-4-Item-24-Favor-static-member-classes-over-nonstatic.md))不應該實現 Serializable。** 它們使用編譯器生成的合成字段存儲對外圍實例的引用,并存儲來自外圍的局部變量的值。這些字段與類定義的對應關系,就和沒有指定匿名類和局部類的名稱一樣。因此,內部類的默認序列化形式是不確定的。但是,靜態成員類可以實現 Serializable 接口。 To summarize, the ease of implementing Serializable is specious. Unless a class is to be used only in a protected environment where versions will never have to interoperate and servers will never be exposed to untrusted data, implementing Serializable is a serious commitment that should be made with great care. Extra caution is warranted if a class permits inheritance. 總而言之,認為實現 Serializable 接口很簡單這個觀點似是而非。除非類只在受保護的環境中使用,在這種環境中,版本永遠不必互操作,服務器永遠不會暴露不可信的數據,否則實現 Serializable 接口是一項嚴肅的事情,應該非常小心。如果類允許繼承,則更加需要格外小心。 --- **[Back to contents of the chapter(返回章節目錄)](/Chapter-12/Chapter-12-Introduction.md)** - **Previous Item(上一條目):[Item 85: Prefer alternatives to Java serialization(優先選擇 Java 序列化的替代方案)](/Chapter-12/Chapter-12-Item-85-Prefer-alternatives-to-Java-serialization.md)** - **Next Item(下一條目):[Item 87: Consider using a custom serialized form(考慮使用自定義序列化形式)](/Chapter-12/Chapter-12-Item-87-Consider-using-a-custom-serialized-form.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>

                              哎呀哎呀视频在线观看