Java的==与equals之辨
=======================原理速记===================================
equals重载后比较内容,==比较指针。否则equls等同于== (Java里源码如此)
所有的“==”都是基于指针级的,也就是说只有它们指向的是同一个对象才被认为是相等.
而对于对象值的相等判断则需要重写并使用.equal()方法
在多数常用类,譬如String中,.equal()已经被默认重写为是值相等的了
两个对象用==号比较,比较的就是 两个对象的引用。
而equals方法比较的是内容。比较String就覆盖了equals方法(自己重定义逻辑相等)
因为内容相等,所以始终输出equals的效果,而==却不一定,例子:
http://www.cnblogs.com/zhxhdean/archive/2011/03/25/1995431.html
================================equals哲学============================
1. 何时需要重写equals()
当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念)。
2. 设计equals()
[1]使用instanceof操作符检查“实参是否为正确的类型”。
[2]对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值。
[2.1]对于非float和double类型的原语类型域,使用==比较;
[2.2]对于对象引用域,递归调用equals方法;
[2.3]对于float域,使用Float.floatToIntBits(afloat)转换为int,再使用==比较;
[2.4]对于double域,使用Double.doubleToLongBits(adouble) 转换为int,再使用==比较;
[2.5]对于数组域,调用Arrays.equals方法。
3. 当改写equals()的时候,总是要改写hashCode()
根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”。
4. hashCode最大的用处是什么呢?
Java中的集合(Collection)有两类,一类是List,再有一类是Set。 前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。
那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢? 这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。Java采用了哈希表的原理, 哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上. 初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。 有了hashCode,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。 如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。 所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
5. 为什么在Hibernate里要重写hashCode和equals这两个方法?
在hibernate中,经常使用set集合来保存相关对象,而set集合是不允许重复的, so, 道理同上。
===========================一道写HashCode的题===========================
一道java hashCode()的面试题
最近面试老是被问到这个问题。。。
public class ValuePair {
public int a = 4, b;
public boolean equals(Object other) {
try {
ValuePair o = (ValuePair) other;
return ((a == o.a) && (b == o.b)) || ((a == o.b) && (b == o.a));
} catch (ClassCastException cce) {
return false;
}
}
public int hashCode() {
// 请选择下边的答案(多选)
}
}
A。return 0;
B. return a;
C. return a+b;
D. return a-b;
E. return a^b;
F. return (a<<16)|b;
请说明理由。
------------------------------------第一种解答----------------------------------------------------------------------
hashCode 的常规协定是:
在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
然后再看重写的equals方法。。
(a==o.a;;b==o.b) || (a==o.b;;b==o.a); 说明交换a,b的值不会对结果产生影响,也要生成相同的hashcode值。
所以选ACE。。。(Cliff评注:A还是不能选)
------------------------------------第二种解答----------------------------------------------------------------------
根据一般约定:
如果2个对象 equals 比较为true,那么hashCode也最好(不是必须)相同。(Cliff:我也比较同意,这是最好,但不是必须)
如果2个对象 equals 比如为false,那么hashCode也最好(不是必须)不同。
因此对于这个题目,如果从纯语法层面考虑,全部都是可选的
但是从程序运行效率来看,最好是该hashCode里,a,b值可以互换,而又尽可能做到不同的a,b值返回不同的值。因为C,E最好.
A. return 0; 效率太低
B. return a; 不满足a,b的互换性
D. return a-b; 不满足a,b的互换性
F. return (a<<16)|b; 不满足a,b的互换性
另外,比如 a * b 也满足互换性,但是效率稍低,毕竟没加法和位运算快
* Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
* If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
* It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
===========================另一个例子,用来熟悉语法===========================
package dd; import java.util.HashSet;
import java.util.Iterator;
import java.util.Set; public class SetTest { public static void main(String[] args) {
// Set<String> set = new HashSet<String>();
// set.add("abc"); //将对象的地址增加到集合中了
// set.add("xyz");
// set.add("abc");
//
// for(Iterator<String> iter = set.iterator(); iter.hasNext();) {
// System.out.println(iter.next());
// } Set<People> set = new HashSet<People>();
set.add(new People("zhangfei"));
set.add(new People("guanyu"));
for (Iterator<People> iter = set.iterator(); iter.hasNext();) {
System.out.println(iter.next().getName());
} // Object object = new Object();
// System.out.println(Integer.toHexString(object.hashCode()));
}
} class People {
private String name; public People(String name) {
this.name = name;
} public String getName() {
return name;
} public boolean equals(Object object) {
if (this == object) { // 第一步
return true;
}
if (object instanceof People) { // 第二步
People people = (People) object;
if (name.equals(people.getName())) { // 第三步,这里很巧妙的使用了String的比较,属于递归调用
return true;
}
}
return false;
} public int hashCode() {
return name.hashCode();
}
}
三、小结
1,如果要用自己的类作为HashMap的key,必须同时覆盖hashCode和equals方法。
2,重写hashCode方法的关键:
(1)对同一个对象调用hashCode()都应该生成同样的值。
(2)hashCode()方法不要依赖于对象中易变的数据,当数据发生变化时,hashCode()就会生成一个不同的散列码,即产生了一个不同的label。
(3)hashCode()不应依赖于具有唯一性的对象信息,例如对象地址。
(4)散列码应该更关心速度,而不是唯一性,因为散列码不必是唯一的。
(5)好的hashCode()应该产生分步均匀的散列码。
参考:
http://blog.csdn.net/lazy_tiger/article/details/1816946
Java的==与equals之辨的更多相关文章
- Java的==与equals之辨,简单解释,很清楚
"=="和equals方法究竟有什么区别? (单独把一个东西说清楚,然后再说清楚另一个,这样,它们的区别自然就出来了,混在一起说,则很难说清楚) ==操作符专门用来比较两个变量的值 ...
- 浅谈Java中的equals和==(转)
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...
- 浅谈Java中的equals和==
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...
- Java hashCode() 和 equals()的若干问题
原文:http://www.cnblogs.com/skywang12345/p/3324958.html 本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() ...
- Java中的equals和hashCode方法
本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...
- Java提高篇——equals()与hashCode()方法详解
java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...
- Java hashCode() 和 equals()的若干问题解答
本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() 与 == 的区别是什么? 3 hashCode() 的作用是什么? 4 hashCode() 和 equa ...
- Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例(转)
Java中==.equals.hashcode的区别与重写equals以及hashcode方法实例 原文地址:http://www.cnblogs.com/luankun0214/p/4421770 ...
- java String的equals,intern方法(转载)
JAVA中的equals和==的区别 ==比较的是2个对象的地址,而equals比较的是2个对象的内容. 显然,当equals为true时,==不一定为true: 基础知识的重要性,希望引起大家的重视 ...
随机推荐
- Velocity中文乱码问题解决方法
http://yonge812.iteye.com/blog/1010290 Velocity中文乱码问题需要注意一下几点: 1.eclipse默认编码方式 2.页面的编码方式 3.volocity模 ...
- 【MyBatis学习08】高级映射之一对一查询
从这一篇博文开始,将总结一下mybatis中的几个高级映射,即一对一.一对多.多对多查询,这篇先总结一下mybatis中的一对一查询. 为了模拟这些需求,事先要建立几个表,不同的表之间将对应上面提到 ...
- 正确的使用字符串String
字符串作为所有编程语言中使用最频繁的一种基础数据类型.如果使用不慎,将会造成不必要的内存开销,为此而付出代价.而要优化此类型,从以下两点入手: 1.尽量少的装箱 2.避免分配额外的内存空间 先从第一点 ...
- Leetcode:integer_to_roman
一. 题目 将给定的数字(阿拉伯数字)转化成罗马数字. 数字不会大于3999 二. 分析 首先我们要知道神马是罗马数字,尽管听说过.但事实上我还真没有记住,于是就google了下,具体 ...
- DNS的概念,用途,DNS查询的实现算法
1.DNS的概念,用途 DNS是由解析器以及域名服务器组成的. 域名服务器是指保存有该网络中所有主机的域名和对应IP地址,并具有将域名转换为IP地址功能的服务器. DNS ...
- 微信支付和微信支付通知基于sdk的说明
前提是,有微信服务号(必须开通了支付功能,也就是说有了商户后台) (注意商户后台 安全目录 的设置,不然即使你写的没错误,也调用不成功) 公众号h5页面写法: (购物车提交--我们上一步已经生成了订 ...
- Android 第三方应用广告拦截实现
前段时间,公司制造的机器里应用装有不良广告,严重影响了儿童客户使用者的思想健康.导致被人投诉. 于是乎.就有了想研发一款相似于360广告屏蔽的应用的念头.嗯.事情就是这样.如今切入主题. 眼下市场上有 ...
- crontab执行脚本与手动执行结果不一致
反正网上说是环境变量问题,我就直接在脚本第二行加入以下代码: source /etc/profile source ~/.bashrc 问题是解决了!
- Java基础08 继承(转载)
继承(inheritance)是面向对象的重要概念.继承是除组合(composition)之外,提高代码重复可用性(reusibility)的另一种重要方式.组合是重复调用对象的功能接口.继承可以重复 ...
- svn备份一般采用三种方式
http://www.cnblogs.com/itech/archive/2011/10/11/2206988.html 备份策略 ============== svn备份一般采用三种方式:1)svn ...