簡體   English   中英

為什么 java.lang.Void 不可序列化?

[英]Why is java.lang.Void not Serializable?

默認情況下可以序列化原始“void”,為什么對象“Void”不擴展 Serializable?

添加示例:

RootImplementation 將有一個編譯錯誤,指出“Void 不在其范圍內”,因為它沒有擴展 Serializable。 盡管將“someMethod”聲明為“void”,但它不會有問題。

public interface Root<R extends Serializable> extends Serializable {
  R someMethod();
}

public class RootImplementation implements Root<Void> {
  public Void someMethod() {
    return null;
  }
}

好的,為了響應您的示例,如果您將方法更改為void它將不起作用,因為該方法必須具有返回類型(即使 Java 現在允許在重寫方法中使用協變返回類型)。 void的討論混淆了這個問題。

您想要做的是將類型參數聲明為“將只返回空值”。 Void 通常是一個不錯的選擇,但要使 Void 起作用,返回類型必須是 Object。 Void 無法實現 API 中的每個接口,因為有人可能想使用它來指示類型參數的 null 返回。

可以通過三種方式來查看您的問題:

  1. Serializable 是一個過於嚴格的類型聲明。 你真的應該使用 Object. 你真的需要它是可序列化的嗎?
  2. 您可以將類型參數聲明為 Serializable,實際上返回 null。 這並不完全表明您每次都返回 null,但這可能就足夠了。
  3. 您可以聲明自己的名為 Null 的類,它實現了 Serializable,可能作為 Root 接口的靜態嵌套類,並在這種情況下將其用作類型參數。 您會發現創建自己的 Null 對象並不少見,即使在標准 JDK 中也有(私有)對象。

javadoc 很清楚:

Void 類是一個不可實例化的占位符類,用於保存對代表 Java 關鍵字的 Class 對象的引用

因為你不能使用它,所以它不需要是可序列化的(反射的東西除外)。


對於第二個問題: void != Void (如果您考慮 != 在非 Java 表達式中)

是的void是一個關鍵字,而Void是一個類。

我會把它作為社區維基放在這里

你可以(反)序列化java.lang.Void b/c 你只能用 null 初始化它。 Java 不在乎一個類是否實現java.io.Serializable如果它是null

代碼結果

t1.VoidOut@19821f
t1.VoidOut@c17164

  public class VoidOut implements java.io.Serializable{
    int x=1;
    Void v = null;

    public static void main(String[] args) throws Throwable{
        VoidOut v = new VoidOut();
        System.out.println(v);
        ByteArrayOutputStream b =new ByteArrayOutputStream(256);
        ObjectOutputStream o = new ObjectOutputStream(b);
        o.writeObject(v);
        o.close();
        ObjectInputStream in =new ObjectInputStream(new ByteArrayInputStream(b.toByteArray()));
        System.out.println(in.readObject());        
    }
}

引用 Javadocs:

Void 類是一個不可實例化的占位符類,用於保存對表示 Java 關鍵字 void 的 Class 對象的引用。

由於該類是不可實例化的,因此不能反序列化。 因此不需要序列化支持。

默認情況下可以序列化原始“void”,為什么對象“Void”不擴展 Serializable?

Void 不攜帶值,因此序列化它是沒有意義的。

這不是說 void != Void 嗎?

沒錯,就像 int != Integer 一樣。 但是當你序列化和反序列化兩個整數時, newint==oldint (我的意思是int ,而不是Integer !!!)。 void不可能有這樣的構造。 什么都不序列化是沒有任何意義的。

只有當你有一個 Void 類型的字段時它才有用,這真的沒有意義。 您還需要實際為其分配一個實例,這再次毫無意義。 只要不做,就可以序列化包含Void字段的類的實例。 為了創建 Void 的實例,您需要使用反射才能使用私有構造函數。

public class VoidSerializerDemo implements Serializable {
    private Void v;

    public static void main(String[] args) throws Exception {
        final VoidSerializerDemo instance = new VoidSerializerDemo();
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        final ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(instance);
        System.out.println("OK: null works");
        final Constructor<Void> constructor = Void.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        instance.v = constructor.newInstance();
        oos.reset();
        System.out.println("Going to throw");
        oos.writeObject(instance);
    }
}

因此,您幾乎不可能需要關心 Void 的可序列化性,不是嗎?

其他人已經解釋了為什么對於永遠無法實例化以實現Serializable的類型沒有意義,以及為什么void不是原始類型或可序列化的。

為了解決您編輯中的代碼,我認為您應該將R extends Serializable綁定更改為R 大多數可Serializable泛型類型不要求它們的類型參數是可Serializable ……它們只是聲明如果您在其中放入不可序列化的內容,它們也將不可序列化。 這通常是一個很好的做法,因為在編譯器級別過於努力地強制執行可序列化可能會咬你(如你所見)。

Void只是為了表明一個方法只能返回null ,遺憾的是沒有辦法直接聲明 null 類型。 因為 jvm Void 只是一個擴展 Object 的普通類,因此不能用於其他類或接口,這使得您的示例中的 Void 無用。

由於您的方法不會返回除 null 之外的任何內容,因此您可以將 Void 替換為以下內容:

public final SerializebaleVoid extends Object implements Serializeable{
    private SerializeableVoid(){}
}

至於調用 void 原語,void 表示沒有值,返回 void 的方法不返回 void 類型的值,而是從字面上不返回任何內容。

如果您使用的是 apache 公共庫,則有一個 org.apache.commons.lang3.ObjectUtils.Null 可以擴展 Serializable。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM