支持最终字段的Java持久性提供程序

支持最终字段的Java持久性提供程序,java,persistence,Java,Persistence,我对Java非常陌生,但我已经养成了一个习惯,尽可能使用final来声明不变性,我认为这是一件好事。(以f#为例) 我读到JPA不支持final字段。休眠,TopLink?我不确定这些,但我现在更喜欢JPA 从理论上讲——比如说通过反射——在创建后修改最终字段是否可能?我猜是。。。否:) 对于持久性解决方案来说,支持具有参数的构造函数无疑是可能的。至少我看不出有什么理由使这不可能。我想映射会有点棘手。 这是另一种解决办法 建议 编辑:我不熟悉不可变的确切定义,所以我在这篇文章中直观地使用了它。在

我对Java非常陌生,但我已经养成了一个习惯,尽可能使用final来声明不变性,我认为这是一件好事。(以f#为例)

我读到JPA不支持final字段。休眠,TopLink?我不确定这些,但我现在更喜欢JPA

从理论上讲——比如说通过反射——在创建后修改最终字段是否可能?我猜是。。。否:)

对于持久性解决方案来说,支持具有参数的构造函数无疑是可能的。至少我看不出有什么理由使这不可能。我想映射会有点棘手。 这是另一种解决办法

建议


编辑:我不熟悉不可变的确切定义,所以我在这篇文章中直观地使用了它。在这里声明不变性意味着声明字段不能更改。抱歉误会了。

这真是个奇怪的想法

通过使字段
为final
,您可以告诉编译器,在对象创建之后,它们将永远不会更改。因此,不坚持这些原则是合理的假设,因为它们永远不会改变。好吧,通过写这篇文章,我假设您拥有java文化,但您提出的问题恰恰相反

在Java中,持久化OBEJCT“始终”被假定为POJO(换句话说,JavaBeans)。JavaBean必须(被视为)有一个空构造函数,该构造函数允许持久性框架等通过Class.newInstance()间接调用空构造函数来构造它

有些字段使用非空构造函数(如IoC容器-Guice、Spring和Tapestry IoC),但它不在Java Bean的范围内,必须将其视为数据对象。

对象不变性(注意不可变对象和声明字段final之间的区别——只有当所有字段都是final时,对象才是不可变的,因此对象的状态在创建后不能更改)是一个非常敏感的话题。我自己喜欢它们,hibernate通过@immutable支持它们

我不知道它在JPA2中的状态,但要回答关于最终字段的问题:您可以使用反射更改它们的值,但是反射在JavaEE环境中受到严重限制

为了说明主要问题:如果POJO是不可变的,那么持久性解决方案将如何重新创建对象?假设您有两个最终的int字段,以及初始化它们的构造函数。持久性层不能有关于它们的顺序或名称的任何信息(因为在编译过程中字段和参数名称会被删除)


Koshuke为此发表了一篇博客(与支持不可变bean的JAXB有关),但现在找不到它。

这可能不是您想要的,但只有getter的非final私有字段很容易支持不变性原则。事实上,编译器可以识别这一点,并生成与声明为final的字段几乎相同的代码


这将要求您认真负责,不要在包含类中更改字段(而
final
将强制执行此操作),但我认为这对于您获得的灵活性来说不是一个很大的代价。

最终字段在通过设计创建后不能修改。否则做是一个非常糟糕的主意,因为有些人可以依赖标准行为


一般来说,持久性框架处理“普通”对象的层次结构。你有只能创建和删除的对象,不能修改。这很奇怪,因为当你创建一个实体时,你为它创建了某种ID。通过这个ID,你将实体连接到其他实体。当你删除旧实体并创建另一个实体时,你(通常)获取具有另一个ID的实体。因此,所有连接(外键)都已断开。这是目标行为吗?

这是一个好问题。实际上,如果字段没有更改,则最好将其声明为final(然后从JMM获得初始化保证)

JPA规范明确了最终字段:

实体类不能是final。 实体类的任何方法或持久实例变量都不能是最终的

无论如何,并非所有实现都遵循此规则并处理最终字段:

  • OpenJPA不支持final字段,即它们被视为瞬态字段。 加载后,使用以下值初始化此类实体的最终字段: 在无参数构造函数中定义

  • 但是,Hibernate实现支持final字段 已在无参数构造函数中初始化的值将替换为存储的值 在数据库中

所以要回答您的问题:是的,有支持final字段的JPA持久性提供程序, 但是,我建议不要在实体类中使用final字段,因为行为没有定义 (事实上,不同的提供商之间是不同的)。此外,我认为
JPA提供程序在构建后更改最终字段,因为这样可能会违反可见性保证。

只读数据库如何?顺便说一句,我只是在探索可能性。其他用例:一个表有多个实体。或者通过工厂方法创建这些实体。对不起,我完全不明白。如果你说的是存在的话ting持久化框架只支持JavaBeans,你可能是对的。但是如果你说不可变对象的固有特性使它们不适合持久化,我完全不同意。有人可能会说Java语言使使用不可变对象变得单调乏味,但框架可以轻松地缓解这些缺陷s、 在回答的第一段中,您似乎假设正在从数据库检索、修改、然后提交一个对象,然后重试