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: 基础知识的重要性,希望引起大家的重视 ...
随机推荐
- MySQL 5.6数据导入报 GTID 相关错误
从阿里云备份数据后还原到本地,用命令行 mysql -uroot -p --default-character-set=<character> -f <dbname> < ...
- 【CODEFORCES】 C. Captain Marmot
C. Captain Marmot time limit per test 1 second memory limit per test 256 megabytes input standard in ...
- 获取表数据的插入SQL
DECLARE @TABLE_NAME VARCHAR(200) SET @TABLE_NAME = 'myFunction' --表名 DECLARE @TABLE_CONDITION VARCHA ...
- jQuery 如何存储,获取和删除 Cookies
jQuery.cookie = function(name, value, options) { if (typeof value != 'undefined') { options = option ...
- Atitit.java 反编译 工具 attilax 总结
Atitit.java 反编译 工具 attilax 总结 1. 三大核心核心引擎——1 2. JAD Jad attitude推荐这个1 2.1. Jdec.2 2.2. 二. 源码开放的 J ...
- flink-connector-kafka consumer的topic分区分配源码
转载请注明原创地址 http://www.cnblogs.com/dongxiao-yang/p/7200599.html flink官方提供了连接kafka的connector实现,由于调试的时候发 ...
- Java并发编程(七)线程封闭
当访问共享的可变数据时,通常需要使用同步.一种避免使用同步的方式就是不共享数据. 如果仅在单线程内访问数据,就不需要同步.这种技术被称为线程封闭(Thread Confinement),它是实现线程安 ...
- Git使用技巧(3)-- 远程操作
Git远程操作详解 作者: 阮一峰 编辑更新:shifu204 日期: 2016年9月1日 Git是目前最流行的版本管理系统,学会Git几乎成了开发者的必备技能. Git有很多优势,其中之一就是远程操 ...
- 使用Hyper-V安装Ubuntu16.04 Server 网络配置
由于最近在研究Docker, 于是需要用到虚拟机,安装Ubuntu 16.04到Hyper-V并部署Docker.这个过程中填平了几个小坑,为了大家以后遇到类似情况节省时间,我将这几个小坑的问题和解决 ...
- 着手打造你的随身系统---将linux装进移动硬盘
将Ubuntu等linux系统安装到移动硬盘--操作系统随身携带 前言 刚刚接触ubuntu,听说可以将linux系统安装到移动硬盘上,所以最近一周都在尝试将ubuntu安装到新买的移动 ...