Java的内存地址与Hibernate的内置对象标识符

在Java语言中,判断两个对象引用变量是否相等,有以下两种比较方式: (1)比较两个变量所引用对象的内存地址是否相同,“==”就是比较的内存地址。此外,在Object类中定义的equals(Object o)也是按内存地址来比较的。如果用户自定义的类没有覆盖equals(Object o)方法,也是按照内存地址来比较的。例如,以下代码用new语句共创建了两个Customer对象,,并定义了三个Customer类型的引用变量,c1,c2,c3:

Customer c1 = new Customer(“Tom”);Customer c2 = new Customer(“Tom’);Customer c3 = c1;c3.setName(“Mike”);

程序执行到第三行如下:

执行到第四行

从以上两图可以看出,C1和C3变量引用同一个Customer对象,而C2变量引用另一个Customer对象,因此,表达式C1 == C3以及C1.equals(C3)都为true,而表达式C1 == C2以及C1.equals(C2)都为false。 (2)比较两个变量所引用的对象值是否相同,Java API中的一些类覆盖了Object类的equals方法,实现按值比较,包括: String类和Date类。 Java包装类,包括:Byte、Integer、Short、Character、Long、Float、Double和Boolean。 例如: 从以上两图可以看出,C1和C3变量引用同一个Customer对象,而C2变量引用另一个Customer对象,因此,表达式C1 == C3以及C1.equals(C3)都为true,而表达式C1 == C2以及C1.equals(C2)都为false。 (2)比较两个变量所引用的对象值是否相同,Java API中的一些类覆盖了Object类的equals方法,实现按值比较,包括: String类和Date类。 Java包装类,包括:Byte、Integer、Short、Character、Long、Float、Double和Boolean。 例如:

String s1 = new String(“hello”);String s2 = new String(“hello”);

尽管s1和s2引用不同的String对象,但是他们的字符串的值都是hello,因此表达式s1==s2是false,而表示是s1.equals(s2)的值是true。 用户自定义的类也可以覆盖Object类的equals(Object o)方法,从而实现按照对象值比较。例如:在Customer类添加如下equals(Object o)方法,使它按客户的姓名来比较两个Customer对象是否相等:

(Object o){if(this == o) return true;if(!o instanceof Customer)return false;final Customer other = (Customer)o;if(this.getName().equals(other.getName()))return true;;}

以下代码用new语句共创建了两个Customer对象,并定义了两个Customer类型的引用变量c1和c2

Customer c1 = new Customer(“Tom”);Customer c2 = new Customer(“Tom”);

尽管c1和c2引用不同的Customer对象,但是他们的name值都是Tome,因此表达式c1 == c2的值是false,而表达式c1.equals(c2)的值是true。 在Java语音中按内存地址来识别或者区分同一个类的不同对象,而关在Hibernate中用对象标识符(OID)来区分对象。OID是关系数据库中的主键(通常为代理主键)在Java对象模型中的等价物。在运行时Hibernate根据OID来维持Java对象和数据库表中记录的对应关系。例如:

Transaction tx = session.beginTransaction();Customer c1 = (Customer)session.load(Customer.class,new Long(1));Customer c2 = (Customer)session.load(Customer.class,new Long(1));Customer c3 = (Customer)session.load(Customer.class,new Long(3));System.out.println(c1==c2);System.out.println(c1==c3);tx.commit();

以上程序中,三次调用了Session的load方法,分别加载OID为1或3的Customer对象,以下是Hibernate三次加载Customer对象的流程。 (1)、第一次加载OID为1的的Customer对象时,先从数据的Customer表中查询ID为1的记录,再创建相应的Customer实例,把它保存在session缓存汇总, 最后把这个对象的引用赋值给变量c1 (2)、第二次加载OID为1的Customer对象时,直接把缓存中的OID为1的Customer对象的引用赋值给c2,因此c1和c1引用同一个Customer对象 (3)、当加载OID为3的Customer对象时,,由于在缓存中不存在这样的对象,所以必须再次到数据库中查询ID为3的Customer对象,再创建相应Customer实例,把他保存在Session缓存中,最后把这个对象的引用赋值给我变量c3. 因此,表达式c1 == c2为true,c1==c3为false。 与表的代理主键对应,OID也是整数类型,Hibernate允许在持久类中把OID定义为以下整数类型。 shot(或包装类Short):2个字节取值范围-2^15 ~ 2^15-1 int(或包装类Integer):4个字节取值范围-2^31~ 2^31-1 long(或包装类Long):8个字节取值范围-2^63 ~ 2^63-1 在对象——关系映射文件中,元素用来设置对象标识符例如:

<id name=”id” type=”long” column=”ID”><generator class=”increment” /></id>

子元素用来设定标识符生成器。Hibernate提供了标识符生成器接口:IdentifierGenerator接口,并且提供了多种内置的实现。下面简单介绍几种: increment:Hibernate自动递增的方式生成标识符,每次增量为1 identity:由底层数据库生成标识符。前提条件是底层数据库支持自动增长字段类型 sequence:根据底层数据库的序列来生成标识符,前提条件是底层数据库支持序列 Hilo:Hibernate根据high/low算法来生成标识符,Hibernate把特定表的字段作为high值,在默认情况下选用hibernate_unique_key表的next_hi字段 native:根据底层数据库对自动生成标识符的支持能力,来选择identity、sequence或Hilo assigned:适用于自然主键,由Java应用程序负责生成标识符,为了能让Java应用程序设置OID,不能把setId()方法声明为private,应该尽量避免使用自然主键。

世界上那些最容易的事情中,拖延时间最不费力。

Java的内存地址与Hibernate的内置对象标识符

相关文章:

你感兴趣的文章:

标签云: