【问题标题】:Why is java.lang.Void not Serializable?为什么 java.lang.Void 不可序列化?
【发布时间】:2011-02-11 15:55:01
【问题描述】:

默认情况下可以序列化原始 '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 从来没有一个实例,我想不出它会是一个类的一个字段的用例。但如果是,您可以随时将其设为瞬态,因为它始终为空。
  • “默认情况下可以序列化原语'void'”是什么意思?没有要序列化的数据...你能举个例子说明你的意思吗?
  • Jon Skeet 可以序列化void!
  • 你可以序列化 Void,主要是 b/c 你不能有类的实例(Constructor.setAccessible(true) 和 Unsafe.allocateInstance(Void.class)不算)
  • 旁注:可序列化意味着是一个隐式/标记接口。

标签: java void


【解决方案1】:

好的,根据您的示例,不,如果您将方法更改为void,它将不起作用,因为该方法必须具有返回类型(即使 Java 现在允许在覆盖的方法中使用协变返回类型)。对void的讨论使问题变得混乱。

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

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

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

【讨论】:

  • 感谢您的回答。 1. 正如 ColinD 所说;大多数只是剥离泛型类型的 Serialziable ,因为类声明本身意味着不要在实现上保存不可序列化的对象。尽管有很多人会使用该接口并进行实现,但我希望它尽可能有帮助,以免出错。 2. 我不希望最终的扩展能够返回除 void 以外的任何东西(或在这种情况下为 null,因为必须使用 Void)。 3.这就是我目前所做的,虽然我想问这个问题,看看是否有人有更好的解决方案。
  • @Tomas Forsman,实现可序列化的类并不意味着它可以被序列化。考虑一下:private void writeObject(ObjectOutputSteam out){throw new NotSerializableException(getClass().getName());} 我确实使用它来确保某些扩展类永远不会达到序列化形式。
【解决方案2】:

javadoc 很清楚:

Void 类是不可实例化的 用于保存引用的占位符类 到代表的 Class 对象 Java 关键字

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


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

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

【讨论】:

    【解决方案3】:

    我会把它作为 comminity-wiki 放在这里

    你可以(反)序列化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());        
        }
    }
    

    【讨论】:

      【解决方案4】:

      引用 Javadocs:

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

      由于类是不可实例化的,所以不能反序列化。因此不需要序列化支持。

      【讨论】:

        【解决方案5】:

        可以序列化 默认情况下原始“无效”,为什么 不是对象“无效”扩展 可序列化?

        Void 不带值,因此序列化它没有意义。

        这不是说 void != Void 吗?

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

        【讨论】:

          【解决方案6】:

          只有当你有一个 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 的可序列化性,不是吗?

          【讨论】:

            【解决方案7】:

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

            要解决您编辑中的代码,我认为您只需将绑定的R extends Serializable 更改为仅R。大多数Serializable 的泛型类型不需要它们的类型参数是Serializable... 它们只是声明如果你在其中放入一些不可序列化的东西,它们也不会是可序列化的。这通常是一个很好的做法,因为在编译器级别过分努力地强制执行可序列化可能会咬到你(如你在此处看到的那样)。

            【讨论】:

              【解决方案8】:

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

              由于您的方法除了 null 之外不会返回任何内容,您可以将 Void 替换为以下内容:

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

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

              【讨论】:

                【解决方案9】:

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-10-31
                  • 2014-09-12
                  • 2013-07-09
                  • 2013-05-26
                  • 2015-04-22
                  • 1970-01-01
                  • 2010-12-27
                  • 2010-11-01
                  相关资源
                  最近更新 更多