<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 12. Serialization(序列化) ### Item 89: For instance control, prefer enum types to readResolve(對于實例控制,枚舉類型優于 readResolve) Item 3 describes the Singleton pattern and gives the following example of a singleton class. This class restricts access to its constructor to ensure that only a single instance is ever created: [Item-3](/Chapter-2/Chapter-2-Item-3-Enforce-the-singleton-property-with-a-private-constructor-or-an-enum-type.md) 描述了單例模式,并給出了下面的單例類示例。該類限制對其構造函數的訪問,以確保只創建一個實例: ``` public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { ... } public void leaveTheBuilding() { ... } } ``` As noted in Item 3, this class would no longer be a singleton if the words implements Serializable were added to its declaration. It doesn’t matter whether the class uses the default serialized form or a custom serialized form (Item 87), nor does it matter whether the class provides an explicit readObject method (Item 88). Any readObject method, whether explicit or default, returns a newly created instance, which will not be the same instance that was created at class initialization time. 如 [Item-3](/Chapter-2/Chapter-2-Item-3-Enforce-the-singleton-property-with-a-private-constructor-or-an-enum-type.md) 所述,如果實現 Serializable 接口,該類將不再是單例的。類使用默認序列化形式還是自定義序列化形式并不重要([Item-87](/Chapter-12/Chapter-12-Item-87-Consider-using-a-custom-serialized-form.md)),類是否提供顯式 readObject 方法也不重要([Item-88](/Chapter-12/Chapter-12-Item-88-Write-readObject-methods-defensively.md))。任何 readObject 方法,不管是顯式的還是默認的,都會返回一個新創建的實例,這個實例與類初始化時創建的實例不同。 The readResolve feature allows you to substitute another instance for the one created by readObject [Serialization, 3.7]. If the class of an object being deserialized defines a readResolve method with the proper declaration, this method is invoked on the newly created object after it is deserialized. The object reference returned by this method is then returned in place of the newly created object. In most uses of this feature, no reference to the newly created object is retained, so it immediately becomes eligible for garbage collection. readResolve 特性允許你用另一個實例替換 readObject[Serialization, 3.7] 創建的實例。如果正在反序列化的對象的類定義了 readResolve 方法,新創建的對象反序列化之后,將在該對象上調用該方法。該方法返回的對象引用將代替新創建的對象返回。在該特性的大多數使用中,不保留對新創建對象的引用,因此它立即就有資格進行垃圾收集。 If the Elvis class is made to implement Serializable, the following readResolve method suffices to guarantee the singleton property: 如果 Elvis 類要實現 Serializable 接口,下面的 readResolve 方法就足以保證其單例屬性: ``` // readResolve for instance control - you can do better! private Object readResolve() { // Return the one true Elvis and let the garbage collector // take care of the Elvis impersonator. return INSTANCE; } ``` This method ignores the deserialized object, returning the distinguished Elvis instance that was created when the class was initialized. Therefore, the serialized form of an Elvis instance need not contain any real data; all instance fields should be declared transient. In fact, **if you depend on readResolve for instance control, all instance fields with object reference types must be declared transient.** Otherwise, it is possible for a determined attacker to secure a reference to the deserialized object before its readResolve method is run, using a technique that is somewhat similar to the MutablePeriod attack in Item 88. 此方法忽略反序列化對象,返回初始化類時創建的特殊 Elvis 實例。因此,Elvis 實例的序列化形式不需要包含任何實際數據;所有實例字段都應該聲明為 transient。事實上,**如果你依賴 readResolve 進行實例控制,那么所有具有對象引用類型的實例字段都必須聲明為 transient。** 否則,有的攻擊者有可能在運行反序列化對象的 readResolve 方法之前保護對該對象的引用,使用的技術有點類似于 [Item-88](/Chapter-12/Chapter-12-Item-88-Write-readObject-methods-defensively.md) 中的 MutablePeriod 攻擊。 The attack is a bit complicated, but the underlying idea is simple. If a singleton contains a nontransient object reference field, the contents of this field will be deserialized before the singleton’s readResolve method is run. This allows a carefully crafted stream to “steal” a reference to the originally deserialized singleton at the time the contents of the object reference field are deserialized. 攻擊有點復雜,但其基本思想很簡單。如果單例包含一個非 transient 對象引用字段,則在運行單例的 readResolve 方法之前,將對該字段的內容進行反序列化。這允許一個精心設計的流在對象引用字段的內容被反序列化時「竊取」對原來反序列化的單例對象的引用。 Here’s how it works in more detail. First, write a “stealer” class that has both a readResolve method and an instance field that refers to the serialized singleton in which the stealer “hides.” In the serialization stream, replace the singleton’s nontransient field with an instance of the stealer. You now have a circularity: the singleton contains the stealer, and the stealer refers to the singleton. 下面是它的工作原理。首先,編寫一個 stealer 類,該類具有 readResolve 方法和一個實例字段,該實例字段引用序列化的單例,其中 stealer 「隱藏」在其中。在序列化流中,用一個 stealer 實例替換單例的非 transient 字段。現在你有了一個循環:單例包含了 stealer,而 stealer 引用了單例。 Because the singleton contains the stealer, the stealer’s readResolve method runs first when the singleton is deserialized. As a result, when the stealer’s readResolve method runs, its instance field still refers to the partially deserialized (and as yet unresolved) singleton. 因為單例包含 stealer,所以當反序列化單例時,竊取器的 readResolve 方法首先運行。因此,當 stealer 的 readResolve 方法運行時,它的實例字段仍然引用部分反序列化(且尚未解析)的單例。 The stealer’s readResolve method copies the reference from its instance field into a static field so that the reference can be accessed after the readResolve method runs. The method then returns a value of the correct type for the field in which it’s hiding. If it didn’t do this, the VM would throw a ClassCastException when the serialization system tried to store the stealer reference into this field. stealer 的 readResolve 方法將引用從其實例字段復制到靜態字段,以便在 readResolve 方法運行后訪問引用。然后,該方法為其隱藏的字段返回正確類型的值。如果不這樣做,當序列化系統試圖將 stealer 引用存儲到該字段時,VM 將拋出 ClassCastException。 To make this concrete, consider the following broken singleton: 要使問題具體化,請考慮以下被破壞的單例: ``` // Broken singleton - has nontransient object reference field! public class Elvis implements Serializable { public static final Elvis INSTANCE = new Elvis(); private Elvis() { } private String[] favoriteSongs ={ "Hound Dog", "Heartbreak Hotel" }; public void printFavorites() { System.out.println(Arrays.toString(favoriteSongs)); } private Object readResolve() { return INSTANCE; } } ``` Here is a “stealer” class, constructed as per the description above: 這里是一個 stealer 類,按照上面的描述構造: ``` public class ElvisStealer implements Serializable { static Elvis impersonator; private Elvis payload; private Object readResolve() { // Save a reference to the "unresolved" Elvis instance impersonator = payload; // Return object of correct type for favoriteSongs field return new String[] { "A Fool Such as I" }; } private static final long serialVersionUID =0; } ``` Finally, here is an ugly program that deserializes a handcrafted stream to produce two distinct instances of the flawed singleton. The deserialize method is omitted from this program because it’s identical to the one on page 354: 最后,這是一個有問題的程序,它反序列化了一個手工制作的流,以生成有缺陷的單例的兩個不同實例。這個程序省略了反序列化方法,因為它與第 354 頁的方法相同: ``` public class ElvisImpersonator { // Byte stream couldn't have come from a real Elvis instance! private static final byte[] serializedForm = { (byte)0xac, (byte)0xed, 0x00, 0x05, 0x73, 0x72, 0x00, 0x05, 0x45, 0x6c, 0x76, 0x69, 0x73, (byte)0x84, (byte)0xe6, (byte)0x93, 0x33, (byte)0xc3, (byte)0xf4, (byte)0x8b, 0x32, 0x02, 0x00, 0x01, 0x4c, 0x00, 0x0d, 0x66, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x53, 0x6f, 0x6e, 0x67, 0x73, 0x74, 0x00, 0x12, 0x4c, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3b, 0x78, 0x70, 0x73, 0x72, 0x00, 0x0c, 0x45, 0x6c, 0x76, 0x69, 0x73, 0x53, 0x74, 0x65, 0x61, 0x6c, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x4c, 0x00, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x74, 0x00, 0x07, 0x4c, 0x45, 0x6c, 0x76, 0x69, 0x73, 0x3b, 0x78, 0x70, 0x71, 0x00, 0x7e, 0x00, 0x02 }; public static void main(String[] args) { // Initializes ElvisStealer.impersonator and returns // the real Elvis (which is Elvis.INSTANCE) Elvis elvis = (Elvis) deserialize(serializedForm); Elvis impersonator = ElvisStealer.impersonator; elvis.printFavorites(); impersonator.printFavorites(); } } ``` Running this program produces the following output, conclusively proving that it’s possible to create two distinct Elvis instances (with different tastes in music): 運行此程序將生成以下輸出,最終證明可以創建兩個不同的 Elvis 實例(具有不同的音樂品味): ``` [Hound Dog, Heartbreak Hotel] [A Fool Such as I] ``` You could fix the problem by declaring the favoriteSongs field transient, but you’re better off fixing it by making Elvis a single-element enum type (Item 3). As demonstrated by the ElvisStealer attack, using a readResolve method to prevent a “temporary” deserialized instance from being accessed by an attacker is fragile and demands great care. 通過將 favorites 字段聲明為 transient 可以解決這個問題,但是最好把 Elvis 做成是一個單元素的枚舉類型([Item-3](/Chapter-2/Chapter-2-Item-3-Enforce-the-singleton-property-with-a-private-constructor-or-an-enum-type.md))。ElvisStealer 所示的攻擊表名,使用 readResolve 方法防止「temporary」反序列化實例被攻擊者訪問的方式是脆弱的,需要非常小心。 If you write your serializable instance-controlled class as an enum, Java guarantees you that there can be no instances besides the declared constants, unless an attacker abuses a privileged method such as AccessibleObject.setAccessible. Any attacker who can do that already has sufficient privileges to execute arbitrary native code, and all bets are off. Here’s how our Elvis example looks as an enum: 如果你將可序列化的實例控制類編寫為枚舉類型, Java 保證除了聲明的常量之外不會有任何實例,除非攻擊者濫用了特權方法,如 `AccessibleObject.setAccessible`。任何能夠做到這一點的攻擊者都已經擁有足夠的特權來執行任意的本地代碼,all bets are off。以下是把 Elvis 寫成枚舉的例子: ``` // Enum singleton - the preferred approach public enum Elvis { INSTANCE; private String[] favoriteSongs ={ "Hound Dog", "Heartbreak Hotel" }; public void printFavorites() { System.out.println(Arrays.toString(favoriteSongs)); } } ``` The use of readResolve for instance control is not obsolete. If you have to write a serializable instance-controlled class whose instances are not known at compile time, you will not be able to represent the class as an enum type. 使用 readResolve 進行實例控制并不過時。如果必須編寫一個可序列化的實例控制類,而該類的實例在編譯時是未知的,則不能將該類表示為枚舉類型。 **The accessibility of readResolve is significant.** If you place a readResolve method on a final class, it should be private. If you place a readResolve method on a nonfinal class, you must carefully consider its accessibility. If it is private, it will not apply to any subclasses. If it is packageprivate, it will apply only to subclasses in the same package. If it is protected or public, it will apply to all subclasses that do not override it. If a readResolve method is protected or public and a subclass does not override it, deserializing a subclass instance will produce a superclass instance, which is likely to cause a ClassCastException. **readResolve 的可訪問性非常重要。** 如果你將 readResolve 方法放在 final 類上,那么它應該是私有的。如果將 readResolve 方法放在非 final 類上,必須仔細考慮其可訪問性。如果它是私有的,它將不應用于任何子類。如果它是包級私有的,它將只適用于同一包中的子類。如果它是受保護的或公共的,它將應用于不覆蓋它的所有子類。如果 readResolve 方法是受保護的或公共的,而子類沒有覆蓋它,反序列化子類實例將生成超類實例,這可能會導致 ClassCastException。 To summarize, use enum types to enforce instance control invariants wherever possible. If this is not possible and you need a class to be both serializable and instance-controlled, you must provide a readResolve method and ensure that all of the class’s instance fields are either primitive or transient. 總之,在可能的情況下,使用枚舉類型強制實例控制不變量。如果這是不可能的,并且你需要一個既可序列化又實例控制的類,那么你必須提供一個 readResolve 方法,并確保該類的所有實例字段都是基本類型,或使用 transient 修飾。 --- **[Back to contents of the chapter(返回章節目錄)](/Chapter-12/Chapter-12-Introduction.md)** - **Previous Item(上一條目):[Item 88: Write readObject methods defensively(防御性地編寫 readObject 方法)](/Chapter-12/Chapter-12-Item-88-Write-readObject-methods-defensively.md)** - **Next Item(下一條目):[Item 90: Consider serialization proxies instead of serialized instances(考慮以序列化代理代替序列化實例)](/Chapter-12/Chapter-12-Item-90-Consider-serialization-proxies-instead-of-serialized-instances.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>

                              哎呀哎呀视频在线观看