Java基础知识陷阱(六)
本文发表于本人博客。
上次说了下equals跟==的问题,今天再来认识一下这个equals()跟hasCode()。上次的代码如下:
class Person{
public String name;
public Person(String name){
this.name = name;
}
public String getName(){
return this.name;
}
@Override
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof Person) {
Person person = (Person)anObject;
if(person.name.equals(this.name)){
return true;
}
}
return false;
}
}
这样对于单纯的2个对象比较是可以达到要求的,但是我们知道在java中存在集合,比如HashSet、HashMap,这2个在判断上逻辑稍微是不同的,这个可以具体看看JDK源码,先看HashSet的add源码:
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
static final long serialVersionUID = -5024744406713321676L;
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<E,Object>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
......
.....
}
我们可以看到当我们使用HashSet对象的add方法的时候,其实其内部使用的是HashMap对象的put方法,而其value值是一个static final的常量,那么可以肯定的是无论增加多少个,那么其的value都是指向一个对象。下面我们再来看看HashMap的put方法:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);
return null;
}
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
return h & (length-1);
}
从上面一些调用我们可以看到在put的时候要先去判断键是否为null,如果是的话putForNullKey()方法进行对整个table数组遍历,先从下标0开始如果对象的key为null就赋值替换掉并返回旧的key;不然就直接增加至最大的下标处。如果键不为null,那么这里就要先计算hashCode来散列来找出它的位置,如果位置上有对象就跟当前的对象对比相同就替换并返回旧value;不然就直接加入并返回null表示添加成功。
这里我们就可以看到不管是HashSet还是HashMap增加对象的时候都有可能用到对象的hascode以及equals方法,所以上次我们单是重写了equals方法不能算是完美解决了,所以还需要重写hasCode方法,这次修改代码如下:
class Person{
public String name;
public Person(String name){
this.name = name;
}
public String getName(){
return this.name;
}
@Override
public boolean equals(Object anObject) {
Boolean result = false ;
if (this == anObject) {
result = true;
}
if (anObject instanceof Person) {
Person person = (Person)anObject;
if(person.getName().equals(this.name)){
result = true;
}
}
System.out.println(result);
return result;
}
@Override
public int hashCode() {
System.out.println("hashCode");
return this.name.hashCode();
}
}
public static void main(String[] args) throws Exception {
Set<Person> set = new HashSet<Person>();
set.add(new Person("www.luoliang.me"));
set.add(new Person("luoliang.me"));
set.add(new Person("www.luoliang.me"));
for(Iterator<Person> iter = set.iterator();iter.hasNext();){
System.out.println(iter.next().getName());
}
}
运行上面的结果:
hashCode
hashCode
hashCode
true
luoliang.me
www.luoliang.me
这样最后的输出,我们还可以推导出当HashSet<String>其原理:当向Set集合增加对象时,首先集合计算器计算要增加对象的hashCode,根据该值得到存放的位置。
当改位置不存在对象时那么集合set认为该对象在集合中不存在直接增加进去;
当改位置存在对象时,接着将准备增加到集合中的对象与改位置的对象进行equals比较,
如果equals返回false,那么集合认为不存在该对象重新计算hashcode增加进去集合中;
如果equals返回true时,集合认为该对象已经存在于集合中就不会再增加该对象到集合中
所以当重写equals的时候必须重写hashCode方法!
下面我们来总结下HashSet跟HashMap的关系:
HashSet是采用HashMap来实现,key就是放进去的对象,value就是一个object常量不变的。
Add方法的时候底层是往Map里put一个对象,其value是全部一样的,不关心的!
HashMap里面有Map.Entry集合。而HashMap底层是用Entry数组的table来维护;
Entry是实现MapEntry,而Entry里面又是维护key,value以及next
调用add方法其实就是调用HashMap的put方法,这个put方法会对hascode以及exuals进行比较
如果相同就替换并返回旧数据value;表示替换成功并未添加只是替换
如果不同添加并返回null,表示添加成功!
使用hascode来计算位置,不会随着set或者map的大小而改变检索对象的时间这样大大有利于提升性能。
这次先到这里。坚持记录点点滴滴!
Java基础知识陷阱(六)的更多相关文章
- Java基础知识陷阱系列
Java基础知识陷阱系列 今天抽空把Java基础知识陷阱有关的文章汇总于此,便于大家查看. Java基础知识陷阱(一) Java基础知识陷阱(二) Java基础知识陷阱(三) Java基础知识陷阱(四 ...
- Java基础知识陷阱(九)
本文发表于本人博客. 今天我来说说关于JAVA多线程知识,有错误请指出.大家都知道JAVA在服务端上处理也有很大优势,很多公司也有在服务器跑JAVA进程,这说明JAVA在处理这个多线程以及并发下也有一 ...
- Java基础知识陷阱(十)
本文发表于本人博客. 上个星期由于时间比较紧所以未能继续写下去,今天再接再厉,专心 + 坚持这样离目标就越来越近了!废话少说说正题,今天我们还是来说说java中比较基础的知识,大家知道编写java程序 ...
- Java基础知识陷阱(二)
本文发表于本人博客. 上次说了一些关于字符串的知识,都是比较基础的,那这次也说下关于对象地址问题,比如传参.先看下面代码: public void changeInt(int a){ a = ; } ...
- java基础知识(六)日期处理
一.日期处理类 在 JDK 1.1 之前,类 Date 有两个其他的函数.它允许把日期解释为年.月.日.小时.分钟和秒值.它也允许格式化和解析日期字符串.不过,这些函数的 API 不易于实现国际化.从 ...
- Java基础知识陷阱(七)
本文发表于本人博客. 上次说了下HashSet和HashMap之间的关系,其中HashMap这个内部有这么一句: static final float DEFAULT_LOAD_FACTOR = 0. ...
- Java基础知识陷阱(四)
本文发表于本人博客. 今天我们来说说关于java继承以及反射有关的问题,大家先看下下面代码,试问可以编译通过不,为什么具体说说原因? public class Test{ public static ...
- Java基础知识陷阱(三)
本文发表于本人博客. 之前都讲了有关字符串的陷阱,那今天来说下关于静态这个东西,这分为静态变量.静态方法,先看下面的代码请问结果输出是什么?: class Person01{ private stat ...
- Java基础知识陷阱(一)
本文发表于本人博客. 事隔好多年了,重新拿起来Java这门语言,看似熟悉其实还很陌生,想想应该梳理下顺便提高下自己.这次先来看看Java里面的String这个对象. 经典的先看下面一段代码,请问最终创 ...
随机推荐
- php 文件下载代码
1.对于一般 $file = "/tmp/dummy.tar.gz"; header("Content-type: application/octet-stream&qu ...
- 用Python获取Linux资源信息的三种方法
方法一:psutil模块 #!usr/bin/env python # -*- coding: utf-8 -*- import socket import psutil class NodeReso ...
- 剑指 offer set 23 n 个骰子的点数
题目 把 n 个骰子扔到地上, 所有骰子朝上一面的点数之和为 s. 输入 n, 打印出 s 所有可能的值出现的概率. 思路 1. 基于递归的求解方法. 深度为 n 的 dfs, 相当于求全排列, 时间 ...
- 调用PostgreSQL存储过程,找不到函数名的问题
PostgreSQL的表,函数名称都是严格区分大小写的,所以在使用的时候没有注意大小写问题容易导致找不到函数名的错误,但最近两天我们发现,如果函数参数使用了自定义的数据类型,也会发生这个问题. 问题描 ...
- 使用pug(jade),以及在vue+webpack中使用pug(jade)
一:在HTML中使用pug 在css中有预处理器less和scss来使我们的样式表更加的简介,那么在HTML中有没有这样的格式呢,答案是有的,那就是pug(前身是jade),效果如下: 转译以后 好, ...
- 二、Android Studio使用——导入jar包,运行、debug都不是问题
[新建AndroidStudio工程,lib导入jar包] 我们的项目代码都在app里面,可以看作是一个Model. src 下面除了我们的代码之外,还有单元测试. 把JAR复制到libs文件 ...
- [Ahoi2014]支线剧情[无源汇有下界最小费用可行流]
3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1538 Solved: 940[Submit][Statu ...
- 构建API
前言 过程,如图: 第一步创建一个帮助类,类里面提供了加密.组装Url等方法,代码如下: using System; using System.Collections.Generic; using S ...
- 【BZOJ3195】[Jxoi2012]奇怪的道路 状压DP
[BZOJ3195][Jxoi2012]奇怪的道路 Description 小宇从历史书上了解到一个古老的文明.这个文明在各个方面高度发达,交通方面也不例外.考古学家已经知道,这个文明在全盛时期有n座 ...
- Objective-C代码学习大纲(2)
2011-05-11 14:06 佚名 otierney 字号:T | T 本文为台湾出版的<Objective-C学习大纲>的翻译文档,系统介绍了Objective-C代码,很多名词为台 ...