英文:
What is the use of @Serial annotation as of Java 14
问题
Java 14在java.io
包中引入了一个新的注解@Serial
。在API文档中对它的简要描述如下:
> 表示被注解的字段或方法是由Java对象序列化规范定义的序列化机制的一部分。
据我理解,该注解类似于@Override
,用于在编译时验证(类似于@Override
),以检查是否正确使用了序列化机制中的方法和字段。但我不明白的是,只要它是序列化机制的一部分,该注解是否会影响序列化/反序列化本身?还是它是改进序列化/反序列化特性设计的第一步,就像这条评论中所提到的那样?
> 所以,如果要完整的图片,把它们都加上:@Serializable,@NotSerializable,@Transient,然后将Serializable标记为弃用…
我对它的用途感到困惑,并且我没有找到任何使用它的代码。你能否提供一个示例代码,突出显示在应使用该注解但未使用时可能出现的问题?
英文:
Java 14 introduces a new annotation @Serial
in the java.io
package. Its brief description in the API docs:
> Indicates that an annotated field or method is part of the serialization mechanism defined by the Java Object Serialization Specification.
As far as I understand the annotation is used for the compile-time validation (similarly to @Override
) to check whether the serialization mechanism methods and fields are used correctly. What I don't understand, does the annotation affect the de/serialization itself as long as it is a part of the serialization mechanism? Or is it a first step to improve the de/serialization feature design in the way suggested with this comment?
> So if it should be the whole picture, add them all: @Serializable, @NotSerializable, @Transient and make Serializable deprecated…
I am confused of its use and I haven't found any code using it. Would you provide a sample code highlighting the issues when the annotation is not used but should be?
答案1
得分: 32
我不明白的是,注解是否会影响序列化本身
不会。它的保留策略是'源代码',因此在编译后被丢弃。字节码不会留下任何痕迹。它无法影响运行时行为(可能会影响编译时代码生成,但这并不会发生)。
就像 @Override
一样,它是可选的,应该在某些情况下在编译时提供一些保证,否则这些问题可能要到运行时才能发现。
例如,拼写错误的 serialVersionUID
:
@Serial
private static final long seralVersionUID = 123L; // 编译时错误,应为 'serialVersionUID'
或者错误的访问修饰符
// 编译时错误,必须是 private
@Serial
public void writeObject(java.io.ObjectOutputStream out) throws IOException
基本上,使用此注解的内容必须与JavaDoc中提到的7个适用元素的描述完全匹配(5个方法,2个字段)。如果方法的签名不匹配,或者修饰符错误,你将会在序列化在运行时失败之前捕获到这个问题。
英文:
> What I don't understand, does the annotation affect the
> de/serialization itself
No. Its retention is 'source', so it's discarded after compilation. The bytecode will contain no trace of it. It has no way to influence runtime behaviour (besides possibly compile-time code generation, which does not happen).
Like @Override
, it is optional and is supposed to give some compile-time assurance for problems which might otherwise not be caught until runtime.
For example, misspelling serialVersionUID
:
@Serial
private static final long seralVersionUID = 123L; // compile-time error, should be 'serialVersionUID'
Or the wrong access modifier
// compile-time error, must be private
@Serial
public void writeObject(java.io.ObjectOutputStream out) throws IOException
Basically, something annotated with this must exactly match the descriptions of the 7 applicable elements mentioned in the JavaDoc (5 methods, 2 fields). If the signature of a method does not match, or the modifiers are wrong, you will catch the problem before serialization fails at runtime.
答案2
得分: 29
这个注解的存在纯粹是为了更好地进行编译时类型检查。在这方面,它类似于 @Override
注解,后者的存在纯粹是为了捕获设计意图,以便人类和工具有更多的信息可用。@Override
注解不会使方法声明成为另一个方法的覆盖 - 这由语言处理,基于方法之间的名称、签名和可访问性进行比较。@Override
做的是断言:“我认为这是一个覆盖,如果我错了,请通过编译错误的形式告诉我。”它也向代码读者通知该方法并不是这个类中新增加的。
因为序列化使用了“魔法”方法和字段名称(诸如 readObject
这样的方法不属于任何接口,它们只是通过序列化赋予了特殊意义),并且确定这些魔法方法是否起作用是棘手的(这些方法不仅必须有正确的名称和参数,还必须具有正确的可访问性和静态性),所以很容易声明一个你认为应该被序列化使用的方法,但序列化并不认同。
@Serial
注解允许你做出类似的断言:你打算将这视为其中一个魔法序列化成员(字段和方法),如果它不符合规定,编译器应该通过错误警告你。它也为代码读者提供了类似的提示,说明该成员将被序列化使用。
大多数开发者可能不会在应用程序和领域代码中使用这个。但库的作者可能会发现它对于加强类型检查和更好捕捉设计意图很有用。
英文:
This annotation exists purely to engage better compile-time type checking. It is analogous in this way to the @Override
annotation, which exists purely to capture design intent, so that humans and tools have more information to work with. The @Override
annotation does not make a method declaration an override of another -- that is handled by the language based on comparing names, signatures, and accessibility between the method and methods in the supertype(s). What @Override
does is assert that "I think this is an override, if I am mistaken, please tell me in the form of a compilation error." And it serves as notice to readers of the code that this method is not new with this class.
Because serialization uses "magic" method and field names (methods like readObject
are not part of any interface, they are just magically given significance by serialization), and the determination of whether the magic works is tricky (methods must not only have the right name and arguments, but the right accessibility and static-ness), it is easy to declare a method that you think is meant to be used by serialization, but for which serialization doesn't agree.
The @Serial
annotation lets you make a similar kind of assertion: that you intend that this is one of those magic serialization members (fields and methods), and if it does not match the profile, the compiler should alert you with an error. And it provides a similar hint to readers that this member is going to be used by serialization.
Most developers probably won't bother with this for application and domain code. But library authors may find it useful as a way to engage stronger type checking and better capture design intent.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论