Hibernate 系列 08 - 对象识别机制
副标题[/!--empirenews.page--]
Hibernate 系列 学习笔记 目录
为了区别不同的对象,有两种识别方法: 1. 内存地址识别(“==”号识别) 2. equals()和hashCode()识别
如果两个对象的内存地址相同,毫无疑问,它们是相同的。 如果要比较的是对象携带的信息,使用内存地址识别就不可用,因为地址不同的对象,它们所代表的的信息可能是一样的。
例如有两个字符串,代码如下: 1 public class CNBlogsTest { 2 public static void main(String[] args) { 3 String str1 = new String("cnblogs"); 4 String str2 = new String("cnblogs"); 5 6 if (str1 == str2) // 判断内存地址是否相同 7 System.out.println("str1和str2的内存地址相同。"); 8 else if(str1.equals(str2)) // 判断它们的值是否相同 9 System.out.println("str1和str2的值相同。"); 10 } 11 }
由于str1和str2是用两个new命令开辟出来的字符串空间,它们的内存地址是不一样的,而它们所携带的信息都是cnblogs,所以运行上例程序打印出来的结果是: str1和str2的值相同。
在Hibernate中Session的操作可能会有一些疑惑。
Session不是线程安全的,不同的Session维护者自己的缓存空间(在Hibernate中用Map实现),这个这个缓存空间存放着纳入了持久层的持久对象。 但是按道理讲,从数据库同一记录取得的字段所组装成的对象应该是同一个对象,然后由不同的Session从数据库同一条记录上分别取得对象,它们的内存地址是不一样的。 尽管它们所携带的信息一致。
如下面的程序所示: 1 Configuration cfg = new Configuration().configure(); 2 SessionFactory sf = cfg.buildSessionFactory(); 3 Session session = sf.getCurrentSession(); 4 Transaction tx = session.beginTransaction(); 5 Object obj1 = session.get(Student.class, 12); 6 Object obj2 = session.get(Student.class, 12); 7 tx.commit(); 8 session.close(); 9 System.out.println(obj1==obj2); // 结果为true 上面这个代码片段最终输出结果为true,表示obj1和obj2引用的是同一对象,它们的内存地址相同。
但如果是下面的代码的话: 1 Configuration cfg = new Configuration().configure(); 2 SessionFactory sf = cfg.buildSessionFactory(); 3 4 // Session1 5 Session session1 = sf.getCurrentSession(); 6 Transaction tx1 = session1.beginTransaction(); 7 Object obj1 = session1.get(Student.class, 12); 8 tx1.commit(); 9 session1.close(); 10 11 // Session2 12 Session session2 = sf.getCurrentSession(); 13 Transaction tx2 = session2.beginTransaction(); 14 Object obj2 = session2.get(Student.class, 12); 15 tx2.commit(); 16 session2.close(); 17 18 System.out.println(obj1==obj2); // 结果为false 19 System.out.println(obj1.equals(obj2)); // 结果为false 以上代码最终的运行结果为false、false。
对于第一个false,是因为不同的Session用不同的Map缓存Session级别的持久对象。 因此,虽然它们是从数据库的同一条记录中取数据,但两个Session把组装的对象放在了不同的内存地址中。 如图所示:
对于第二个false,有的朋友可能会有点儿懵逼,equals()方法不就是比较对象信息的嘛?既然是同一条记录组装的对象,为什么还是false嘞? 这是因为Student类默认的equals()方法继承自java.lang.Object类,Object类的equals()方法的源码如下: 1 package java.lang; 2 public class Object { 3 public boolean equals(Object obj) { 4 return (this == obj); 5 } 6 }
可以看到,Object类的equals()方法使用的仍是内存地址判断,由于obj1和obj2的内存地址不一样,所以使用继承自Object的equals()方法得到的依然还是false。
平时所熟悉的String类的equals()方法是重写了Object的equals()方法。 当调用String类的a.equals(b)方法时,是将a字符串和b字符串一个字符一个字符进行比较,因此String类的equals()方法可以比较不同内存地址的字符串是否相同。 String类的equals()方法源码如下: 1 package java.lang; 2 3 import java.io.ObjectStreamField; 4 import java.io.UnsupportedEncodingException; 5 import java.nio.charset.Charset; 6 import java.util.ArrayList; 7 import java.util.Arrays; 8 import java.util.Comparator; 9 import java.util.Formatter; 10 import java.util.Locale; 11 import java.util.Objects; 12 import java.util.StringJoiner; 13 import java.util.regex.Matcher; 14 import java.util.regex.Pattern; 15 import java.util.regex.PatternSyntaxException; 16 17 public final class String 18 public boolean equals(Object anObject) { 19 if (this == anObject) { 20 return true; 21 } 22 if (anObject instanceof String) { 23 String anotherString = (String)anObject; 24 int n = value.length; 25 if (n == anotherString.value.length) { 26 char v1[] = value; 27 char v2[] = anotherString.value; 28 int i = 0; 29 while (n-- != 0) { // 只要两个String之中有一个字符不同,则认为二者不同 30 if (v1[i] != v2[i]) 31 return false; 32 i++; 33 } 34 return true; 35 } 36 } 37 return false; 38 } 39 }
同理,要实现Student类的信息比较,可以自己实现equals()和hashCode()方法。 一个方法时,通过getStudentNo()方法取得对象的studentNo值并加以比较。 (编辑:淮北站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |