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

时间:2011-02-11 15:55:01

标签: java void

默认情况下可以序列化原语'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;
  }
}

9 个答案:

答案 0 :(得分:5)

好的,作为对你的例子的回应,如果你把方法改为void它就行不通,因为该方法必须有一个返回类型(即使Java现在允许在重写方法中使用协变返回类型) 。对void的讨论混淆了这个问题。

您要做的是将类型参数声明为“将只返回null”。 Void通常是一个很好的选择,但是要使Void工作,返回类型必须是Object。 Void无法实现API中的每个接口只是因为有人可能希望使用它来指示类型参数的null返回。

有三种方法可以查看您的问题:

  1. Serializable是一种过于严格的类型声明。你应该真正使用Object。你真的需要它是Serializable吗?
  2. 您可以将type参数声明为Serializable,并且实际上返回null。这并不能完全表明你每次都返回null,但这可能就足够了。
  3. 您可以声明自己的名为Null的类,它实现Serializable,可能作为Root接口的静态嵌套类,并在此情况下将其用作类型参数。您会发现制作自己的Null对象并不常见,即使在标准JDK中也存在(私有)对象。

答案 1 :(得分:4)

javadoc很清楚:

  

Void类是不可实现的   占位符类来保存引用   到表示对象的Class对象   Java关键字

因为你不能使用它,所以它不需要是Serializable(反射东西除外)。


对于第二个问题:void!= Void(如果你想到的话!=在非java表达式中)

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

答案 2 :(得分:2)

我会把它作为comminity-wiki

放在这里

你可以(de)序列化java.lang.Void b / c你只能用null初始化它。如果一个类实现java.io.Serializable null,那么Java并不关心。

代码结果

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());        
    }
}

答案 3 :(得分:1)

引用Javadocs:

  

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

由于该类是不可实例化的,因此无法反序列化。 Ergo不需要序列化支持。

答案 4 :(得分:0)

  

可以序列化   默认为原始'void',为什么呢   不是'Void'对象延伸   序列化?

Void没有值,因此序列化它是没有意义的。

  

这是不是意味着虚空!=无效?

是的,就像int!=整数。但是当你序列化和反序列化两个整数时,newint == oldint(我的意思是int,而不是Integer !!!)。 void不可能有这样的结构。将序列化没有任何意义。

答案 5 :(得分:0)

只有你有一个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的可串行性,不是吗?

答案 6 :(得分:0)

其他人已经解释了为什么对于一个永远无法实例化以实现Serializable的类型以及为什么void不是原始的或可序列化的类型没有意义。

要解决编辑中的代码,我认为您应该只将R extends Serializable更改为R。大多数Serializable的通用类型不要求它们的类型参数为Serializable ......它们只是声明如果你在其中放入一些不可序列化的东西,它们也不会是可序列化的。这通常是一种很好的做法,因为在编译器级别上努力强制执行可序列化可能会让你感到困惑(如你所见)。

答案 7 :(得分:0)

Void仅用于表明方法只能返回null,遗憾的是没有办法直接声明null类型。对于jvm,Void只是一个扩展Object的普通类,因此不能用于其他类或接口,这使得Void对你的例子毫无用处。

由于你的方法不会返回null,你可以用以下内容替换Void:

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

对于调用void一个原语,void表示没有值,返回void的方法不返回void类型的值,而是字面上不返回任何内容。

答案 8 :(得分:0)

如果您使用的是apache commons库,则有一个org.apache.commons.lang3.ObjectUtils.Null可以扩展Serializable。