Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 有没有办法为Hibernate托管对象声明最终字段?_Java_Hibernate_Final_Pojo - Fatal编程技术网

Java 有没有办法为Hibernate托管对象声明最终字段?

Java 有没有办法为Hibernate托管对象声明最终字段?,java,hibernate,final,pojo,Java,Hibernate,Final,Pojo,我刚刚开始学习Hibernate,到目前为止,我看到的所有示例都与Hibernate文档中的教程非常相似: package org.hibernate.tutorial.domain; import java.util.Date; public class Event { private Long id; private String title; private Date date; public Event() {} /* Accessor m

我刚刚开始学习Hibernate,到目前为止,我看到的所有示例都与Hibernate文档中的教程非常相似:

package org.hibernate.tutorial.domain;
import java.util.Date;

public class Event {

    private Long id;
    private String title;
    private Date date;

    public Event() {}

    /* Accessor methods... */
}
具体来说:没有一个字段被声明为
final
,并且必须有一个无参数构造函数,以便Hibernate框架可以实例化类并设置其字段

但是这里有一件事-我真的不喜欢在我可以避免的情况下以任何方式使我的类可变(Java实践:不可变对象为这样做提供了一个非常有力的理由)。那么,即使我将每个字段都声明为“final”,有没有办法让Hibernate工作呢

我知道Hibernate使用反射来实例化它的类,因此需要能够调用某种构造函数,而不必冒选择错误构造函数或将错误值传递给其参数的风险,因此调用无参数构造函数并一次设置一个字段可能更安全。然而,难道不能提供必要的信息来休眠,以便它可以安全地实例化不可变的对象吗

public class Event {

    private final Long id;
    private final String title;
    private final Date date;

    public Event(@SetsProperty("id") Long id,
        @SetsProperty("title") String title,
        @SetsProperty("date") Date date) {

        this.id = id;
        this.title = title;
        this.date = new Date(date.getTime());
    }

    /* Accessor methods... */
}

@setproperty
注释当然是虚构的,但似乎不应该超出范围。

这听起来好像不是Hibernate的用例,因为它执行的许多操作都与可变状态有关:

  • 合并对象
  • 脏状态检查
  • 冲洗变化
也就是说,如果您担心不变性,您可以选择在对象周围提供包装,并使用复制构造函数:

public class FinalEvent {
    private final Integer id;

    public FinalEvent(Event event) {
        id = event.id;
    }
}
但这确实意味着额外的工作


现在我想起来了,hibernate会话通常是线程绑定的,这至少使最终的字段安全发布的一个好处无效


您还希望最终字段有什么其他好处?

不可变对象是指没有修改其状态(即字段)的方法的对象。字段不必是最终字段。因此,您可以删除所有的mutator,并将Hibernate配置为使用字段access而不是accessor,或者您可以将no-arg构造函数和mutator标记为不推荐使用。这是一种解决方法,但总比没有好。

您可以通过使用构建器模式来实现所需的结果。不久前,我在Hibernate论坛上读到了关于这个想法的讨论(尽管我自己从未实现过…

这个想法也困扰了我很长时间。我最近尝试的一个想法是,为模型类定义只读接口,让DAO和任何工厂在对象上返回这些接口。这意味着,即使实现是可变的,但一旦离开DAO/factory对象,就不能再对其进行调整

像这样:

public interface Grape {
  public Color getColor();
}

public class HibernateGrapeDao {
  public Grape findGrape(int grapeId) {
    HibernateGrape grape = hibernate.find(...
    return grape;
  }
}

class HibernateGrape implements Grape {
 ....
}

甚至可能希望将实现类包保持为dao包的私有包,因此没有人可以直接处理它们。多做一点工作,但从长远来看可能有助于保持清洁。显然,在处理整个平等/身份事务时要小心。

实际上,在JDK 1.5+中,hibernate可以(通过反射)处理最终字段的更改。创建一个受保护的默认构造函数(),将字段设置为某些默认值/null等。。。Hibernate可以并且将在实例化对象时覆盖这些值

这一切都是由于对Java1.5内存模型的更改而实现的,这些更改是为了启用序列化/反序列化而进行的(允许final不是final)

public class Event {

private final Long id;
private final String title;
private final Date date;

// Purely for serialization/deserialization
protected Event() {
    id = null;
    title = null;
    date = null;
}

public Event(Long id, String title, Data date) {
    this.id = id;
    this.title = title;
    this.date = date;
}

/* Accessor methods... */

}

用@Access(AccessType.FIELD)为类添加注释,然后可以将字段设置为最终字段。像这样:

@Access(AccessType.FIELD)
public final class Event {

    private final Long id;
    private final String title;
    private final Date date;

    private Event() {
        id = null;
        title = null;
        date = null;
    }

    public Event(Long id, String title, Date date) {
        this.id = id;
        this.title = title;
        this.date = date;
    }
}

+1:关于使用包装类的好主意-当需要最终类/字段时,它看起来是一个很好的解决方案。通过使可变版本仅对数据访问类可见,甚至可以避免在外部使用哪个版本(可变版本vs.包装器)的歧义。至于使用final,我的主要原因是,通常更容易保证(而不是假设)每个字段在构建时只分配一次。我们有很多数据,这些数据在使用它的JVM的整个生命周期中都是恒定的,因此澄清这一点很有帮助。最终字段可以防止用户意外地分配他们不应该拥有的内容,并引入一个微妙的错误。如果你知道某些事情永远不会改变,你就要让它成为最终的。如果您发现它应该更改,您可以随时删除该约束。@corsiKa访问器定义了该逻辑:如果您不需要更改某些属性,只需不创建setter即可。但是,我同意代码必须尽可能严格,但不能采用hibernate的方法。+1:谢谢-对于制作包装类不可能/不实用的情况,这也很有帮助(删除setter并使用基于字段的访问)。我不能说,因为我对幕后正在进行的功夫反思太激动了——私人领域实际上并不私人。有点让我觉得我应该先添加一些@readthehibernate电子书,然后再为那些不太熟悉Hibernate工作细节的用户(比如我)使用类标签。