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