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

为什么java.lang.Void不可序列化?,java,void,Java,Void,可以按照默认值序列化基元“void”,为什么对象“void”不扩展Serializable 添加示例: RootImplementation将有一个编译错误,说明“Void不在其范围内”,因为它不扩展Serializable。 虽然“someMethod”会用“void”声明,但这不会有问题 public interface Root<R extends Serializable> extends Serializable { R someMethod(); } public

可以按照默认值序列化基元“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;
  }
}
公共接口根扩展可序列化{
R-somethod();
}
公共类Root实现实现了Root{
公共方法(){
返回null;
}
}
javadoc很清楚:

Void类是一个不可证明的类 用于保存引用的占位符类 到表示 Java关键字

因为您不能使用它,所以它不需要序列化(反射内容除外)


关于第二个问题:无效!=Void(如果您正在考虑!=在非java表达式中)

void
是一个关键字,
void
是一个类

引用Javadocs:

Void类是一个不可实例化的占位符类,用于保存对表示Java关键字Void的类对象的引用

由于该类不可实例化,因此无法对其进行反序列化。因此,不需要序列化支持

可以序列化 每个默认值的基元“void”,为什么 不是对象“Void”扩展 可序列化

Void不携带值,因此序列化它是没有意义的

这不是意味着空虚吗!=空虚


正确,与int一样!=整数。但是当您序列化和反序列化两个int时,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);
    }
}
公共类VoidSerializerDemo实现可序列化{
私人无效v;
公共静态void main(字符串[]args)引发异常{
最终VoidSerializerDemo实例=新的VoidSerializerDemo();
最终ByteArrayOutputStream bas=新ByteArrayOutputStream();
最终ObjectOutputStream oos=新ObjectOutputStream(BAS);
oos.writeObject(实例);
System.out.println(“确定:空工作”);
最终构造函数=Void.class.getDeclaredConstructor();
constructor.setAccessible(true);
instance.v=constructor.newInstance();
oos.reset();
System.out.println(“即将抛出”);
oos.writeObject(实例);
}
}

因此,您极不可能需要关心Void的可序列化性,不是吗?

其他人已经解释了为什么不能实例化一个类型来实现
Serializable
是没有意义的,为什么
Void
不是一个原语或可序列化的


要解决编辑中的代码问题,我认为您应该将
R extends Serializable
绑定更改为just
R
。大多数可序列化的泛型类型不要求其类型参数为可序列化的。。。它们只是简单地声明,如果您在其中放入不可序列化的内容,它们也将不可序列化。这通常是一个很好的实践,因为在编译器级别过于努力地强制可序列化性可能会对您造成伤害(如您在这里看到的)。

好的,作为对您的示例的响应,如果您将方法更改为
void
,它将不起作用,因为该方法必须具有返回类型(即使Java现在允许在重写的方法中使用协变返回类型)

您要做的是将类型参数声明为“will just return null”。对于这一点,Void通常是一个不错的选择,但要使Void工作,返回类型必须是Object。Void不能实现API中的每个接口,因为可能有人想用它来指示类型参数的null返回

有三种方法可以解决您的问题:

  • Serializable是一个过度限制的类型声明。您应该真正使用对象。您真的需要它可以序列化吗
  • 您可以将类型参数声明为可序列化,实际上返回null。这并不完全表明您每次都返回null,但这可能就足够了
  • 您可以声明自己的名为Null的类,该类实现可序列化,可能作为根接口的静态嵌套类,并在本例中将其用作类型参数。您会发现创建自己的Null对象并不少见,即使在标准JDK中也有(私有)对象

  • Void
    仅用于表明方法只能返回
    null
    ,遗憾的是,无法直接声明null类型。因为jvm Void只是一个普通的类扩展对象,因此不能用于其他类或接口,这使得Void对于您的示例来说毫无用处

    由于您的方法只返回null,因此可以使用以下内容替换Void:

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

    至于调用void原语,void表示没有值,返回void的方法不会返回void类型的值,相反,它实际上不会返回任何内容。

    我将把它作为community wiki放在这里

    您可以(反)序列化
    java.lang.Void
    b/c您可以仅使用null对其进行初始化。java不关心类是否实现了
    java.io.Serializable
    ,如果它是
    null

    守则的结果

    t1.VoidOut@19821f t1.VoidOut@c17164
    如果您使用的是apache commons库,则有一个org.apache.commons.lang3.Objec
      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());        
        }
    }