精通Hibernate——Java的内存地址与Hibernate的内置对象标识符
2015-07-25 20:27
591 查看
在Java语言中,判断两个对象引用变量是否相等,有以下两种比较方式:
(1)比较两个变量所引用对象的内存地址是否相同,“==”就是比较的内存地址。此外,在Object类中定义的equals(Object o)也是按内存地址来比较的。如果用户自定义的类没有覆盖equals(Object o)方法,也是按照内存地址来比较的。例如,以下代码用new语句共创建了两个Customer对象,,并定义了三个Customer类型的引用变量,c1,c2,c3:
程序执行到第三行如下:
执行到第四行
从以上两图可以看出,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。
例如:
尽管s1和s2引用不同的String对象,但是他们的字符串的值都是hello,因此表达式s1==s2是false,而表示是s1.equals(s2)的值是true。
用户自定义的类也可以覆盖Object类的equals(Object o)方法,从而实现按照对象值比较。例如:在Customer类添加如下equals(Object o)方法,使它按客户的姓名来比较两个Customer对象是否相等:
以下代码用new语句共创建了两个Customer对象,并定义了两个Customer类型的引用变量c1和c2
尽管c1和c2引用不同的Customer对象,但是他们的name值都是Tome,因此表达式c1 == c2的值是false,而表达式c1.equals(c2)的值是true。
在Java语音中按内存地址来识别或者区分同一个类的不同对象,而关在Hibernate中用对象标识符(OID)来区分对象。OID是关系数据库中的主键(通常为代理主键)在Java对象模型中的等价物。在运行时Hibernate根据OID来维持Java对象和数据库表中记录的对应关系。例如:
以上程序中,三次调用了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
在对象——关系映射文件中,元素用来设置对象标识符例如:
子元素用来设定标识符生成器。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,应该尽量避免使用自然主键。
(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对象是否相等:
public boolean equals(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; else return false; }
以下代码用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,应该尽量避免使用自然主键。
相关文章推荐
- Spring中实现多数据源事务管理
- [Java Web]Struts2加起来(一个)
- 一个经典例子让你彻彻底底理解java回调机制
- 《深入理解java虚拟机》:类的初始化
- Java 中 Map 的使用
- java 基础之枚举
- java 基础之枚举
- Spring AOP 异常:IllegalArgumentException: error at ::0 can't find referenced pointcut
- Struts2的配置文件——web.xml
- java之可变参数
- 与阿根廷一起学习Java Web四个发展:对于信息传输和信息传输
- java之可变参数
- java多线程学习笔记——有关多线程的文章连接汇总
- Java 学习笔记(2015.7.20~24)
- 《深入浅出struts2》--第七章,类型转换
- springMVC的前端控制器的配置
- Struts基础
- Java之增强的for 循环
- Java之增强的for 循环
- 【javaweb】Session原理以及浏览器禁止Cookie之后服务器如何获取Session