为什么Java

时间:2017-08-15 13:25:58

标签: java

serialVersionUID在我看来有一个非常宽松的规范。开发具有可序列化接口的类的任何主体都可以使用InvalidClassException来烧伤他的手。另外,我看到一个使用int作为数据类型而不是长的开发者。

所以,我的问题为什么Java设计人员和开发人员没有做更具体的事情,就像我们实现可序列化时一样,我们必须实现一个设置serialVersionUID的方法,就像hashcode方法一样。

那么,我错过了什么?对我来说似乎不是一把双刃剑。

更新1:

我的坏我给出了一个错误的例子,比较一个类级别的东西和一个实例级别的东西。由于这个原因,我在不同的公司看到了许多生产问题。但我的一般想法是不能让编译器以任何方式更加严格。

3 个答案:

答案 0 :(得分:5)

请记住要求:

  • 构成ID的字节必须存在 表示序列化对象的字节流
  • 除非您发明“顶部”的东西,否则实现目标的唯一方法是使用字段
  • 对于类的所有对象,ID必须相同,因此ID的来源应为静态

现在退后一步:

  • 静态方法没有多态性
  • 从这个意义上讲,如果你使用静态字段或在序列化对象时调用静态方法来获取ID字节
  • ,那就没有区别了
  • 但是你要将这些字节写入流中

结论:使用静态字段可解决以上所有问题 。当您使用方法时 - 您仍然需要创建该字段。让它沉入:当使用方法时,实现必须调用方法,将其作为字段写入字节流 - 并且在读取字节流时,需要消耗该数字 - 因为它无法映射到“真正的“班上的领域。比较一下:有一个静态字段被写入字节流并从那里读取。

所以 - 从技术的角度来看,在ID中以某种方式集成的自然方式是在类上要求静态字段。

当然你可能已经发明了别的东西。现代java 可能使用了注释。但是,当Java被发明时,这种注释的使用并不存在(并且这种序列化从第1天开始就在Java中)。 然后:现代java首先不使用“字节流”定向序列化。

或者斯蒂芬建议的答案 - 您可以根据班级的当前内容计算该ID。但同样:这项技术是20年前发明的。那时候,计算 id可能需要花费你1,5,10秒。将其与读取静态字段的努力进行比较。

答案 1 :(得分:4)

  

所以,我的问题为什么Java设计人员和开发人员没有做更具体的事情,就像我们实现可序列化时一样,我们必须实现一个设置serialVersionUID的方法,就像hashcode方法一样。

如果我理解正确,你说应该有一种计算serialVersion的方法。我可以看到这个问题:

  1. 应用程序如何计算出合适的串行版本?请注意,必须根据类型信息计算...而不是字段值。

  2. 在运行时(重复)计算串行版本会很昂贵。

  3. 如果我们的懒惰程序员不使用" serialver"计算正确版本号的工具,同样懒惰的程序员可能会实现这个(假设的)方法来返回一个伪造的数字......我们回到了我们开始的地方。

  4. 有些用例不是故意更改串行版本ID。

  5. 没有。懒惰程序员问题的真正解决方案是代码审查。

    或者......也许......工具要么重新生成serialVersion常量,要么将它们标记为可疑。

    请注意,工具无法选择所有可能出现问题的情况。但是,代码审查员也不能。代码审查员会感到疲倦,需要付费等等。

    (最后,如果某些IDE没有将常量设置为-1作为快速修复,可能是个好主意...)

      

    但我的一般想法是不能让编译器以任何方式更加严格。

    这不是编译器的事情。它是特定库类集的运行时行为。这些类使用Unsafe ...但编译器不知道serialVersionID变量的重要性。

答案 2 :(得分:1)

  

为什么Java设计人员和开发人员没有[让我们]必须这样做   实现一个设置serialVersionUID

的方法

serialVersionUID是与该类相关的数据。它不是与该类的单个实例相关的数据。

如果我们有一个界面,如:

interface MySerializable
{
    long getSerialVersionUID(); 
}
然后我们可以像这样实现:

class Foo implements MySerializable
{
    private String myField;

    //...

    public long getSerialVersionUID()
    {
        if(myField.equals("hello"))
        {
            return 1L;
        }
        else
        {
            return 2L
        }
    }
}

这没有意义。版本不能依赖于实例。

既然我们有注释,我眼中的一个好解决方案是编写@Serializable注释。我更喜欢这个,因为与序列化相关的任何事情都只是元数据。添加一个与该类行为完全无关的额外字段只会让水变得混乱。

@Serializable(ID = "1")
class Foo
{
    //...
}

当然,注释是最近添加的,因此在serialVersionUID被设计时,这不是一个选项。