涨知识:equals 和 == 你真的了解吗?
基本概念
- ==是运算符,比较的是两个变量是否相等;
- equals()是Object方法,用于比较两个对象是否相等
看一下源码:
- public boolean equals(Object anObject) {
- if (this == anObject) {
- return true;
- }
- if (anObject instanceof String) {
- String anotherString = (String)anObject;
- int n = value.length;
- if (n == anotherString.value.length) {
- char v1[] = value;
- char v2[] = anotherString.value;
- int i = 0;
- while (n-- != 0) {
- if (v1[i] != v2[i])
- return false;
- i++;
- }
- return true;
- }
- }
- return false;
- }
当this==anObject的时候,返回true,即this 和 obj引用同一个对象时,才会返回true;
还有就是当判断字符串相等的时候,当anObject是String类型,并且长度和内容一样的时候,返回true;
小结
只有当引用一个对象的时候,才会返回true。
而我们在实际用equals()方法的时候,我们往往不是为了判断两个引用的是一个对象,因此我们此时要重写equals()方法;
equals()有以下的公约必须遵守:
- 对称性:x,y非空,如果x.equals(y)返回true,那么y.equals(x)必为true;
- 自反性:对于任何非null的引用值x,x.equals(x)必须返回true;
- 传递性:x,y,z非空,x.equals(y),y.equals(z)返回true,那么x.equals(z)必为true;
- 一致性:x,y非空,只要对象信息没有被修改,那么多次调用x.equals(y)的结果肯定都一样;
- 对于任何非null的引用值x,x.equals(null)必须返回false;
因此,我们一般有以下推论:
- 任何情况下,x.equals(null),永远返回是false;x.equals(和x不同类型的对象)永远返回是false。
- equals()相等的两个对象,hashcode()一定相等;反过来:hashcode()不等,一定能推出equals()也不等;
- hashcode()相等,equals()可能相等,也可能不等
现在我们可以这样解释了:
1、因为是按照hashCode来访问小内存块,所以hashCode必须相等。
2、HashMap获取一个对象是比较key的hashCode相等和equal为true。
3、比如对象ObjectA和ObjectB他们都有属性name,那么hashCode都以name计算,所以hashCode一样,但是两个对象属于不同类型,所以equal为false。所以hashCode相等,却可以equal不等
当我们编写完成了equals()方法的时候,我们要问自己三个问题:它是否是对称的、传递的、一致的;
问题:重写equals()方法的时候总要重写hashcode()方法,为什么要重载equal方法?
在每个重写equals()的类中,我们必须重写hashcode()方法;如果不这样做,会违反hashcode()的公约:
- 1.只要对象的信息没有改变,那么对一个对象调用多次,hashcode()方法都必须始终如一的返回同一个整数;
- 2.如果两个对象根据equals()方法比较是相等的,那么调用这两个对象中任意一个对象的hashcode()方法都必须产生同样的结果;
- 3.如果两个对象根据equals()方法比较是不相等的,那么调用这两个对象中任意一个对象的hashcode()方法不一定产生同样的结果;
相等的对象必须有相同的散列码
代码示例
- import java.util.HashSet;
- import java.util.Set;
- /**
- * hashcode和equals方法
- * HashMap中有一个put方法,put(key,value)key是无序不可重复的
- */
- public class SetTest2 {
- public static void main(String[] args)
- {
- //创建集合
- Set es = new HashSet();
- Employee e1 = new Employee("1000","tao");
- Employee e2 = new Employee("1000","tao");
- // Employee e2 = new Employee("1001","tao1");
- Employee e3 = new Employee("1002","tao2");
- Employee e4 = new Employee("1003","tao3");
- Employee e5 = new Employee("1004","tao4");
- Employee e6 = new Employee("1005","tao5");
- // System.out.println(e1.equals(e2));
- // System.out.println(e2);
- System.out.println(e1.hashCode());
- System.out.println(e2.hashCode());
- es.add(e1);
- es.add(e2);
- es.add(e3);
- es.add(e4);
- es.add(e5);
- es.add(e6);
- System.out.println(es.size());
- }
- }
- class Employee{
- String num;//员工编号
- String name;
- Employee(String num,String name){
- this.num = num;
- this.name = name;
- }
- //重写equals方法,如果员工编号相同并且名字相同,则是同一个对象
- public boolean equals(Object o){
- if (this == o){
- return true;
- }
- if (o instanceof Employee){
- Employee e = (Employee) o;
- if (e.num.equals(this.num) && e.name.equals(this.name))
- {
- return true;
- }
- }
- return false;
- }
- //重写Hashcode方法
- public int hashCode(){
- //以员工编号分组,可散列均匀分布
- return num.hashCode();
- }
- }
- hashCode()的底层实现:
- public int hashCode() {
- int h = hash;
- if (h == 0 && value.length > 0) {
- char val[] = value;
- for (int i = 0; i < value.length; i++) {
- h = 31 * h + val[i];
- }
- hash = h;
- }
- return h;
- }
可以看到最终hash = s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1];
涨知识:equals 和 == 你真的了解吗?的更多相关文章
- Java易混小知识——equals方法和==的区别
一.equals方法和==的区别 1.equals是String对象的方法,可以通过".“调用. 2.== 是一个运算符. 二.常用的比较用法 1.基本数据类型比较. equals和==都比 ...
- 涨知识Style
1.用Access作为后台数据库支撑,书写一个C#写入记录的案例 示例1: using System.Data.OleDb; string sql = "insert into 表 (列1, ...
- Camel——涨知识了,骆驼命名法
骆驼式命名法(Camel-Case)又称驼峰命名法,是电脑程式编写时的一套命名规则(惯例).正如它的名称CamelCase所表示的那样,是指混合使用大小写字母来构成变量和函数的名字.程序员们为了自己的 ...
- 涨知识,涨知识 :ThinkPHP框架下Where条件查询Mysql数据库某字段是否为空
代码虐我千百遍,我对代码如初恋~ 问题: 查询某字段app_date数据是否为NULL,正常我们实现的办法是: $map['app_data'] = array('eq','null'); $data ...
- main方法原来只要放在public static类中就能跑,涨知识了
接口中可以装在嵌套类对象. public interface ClassInterface { void howdy(); class Test implements ClassInterface { ...
- 你可能不知道的 10 条 SQL 技巧,涨知识了!
转自:http://mp.weixin.qq.com/s?__biz=MjM5NzM0MjcyMQ==&mid=2650076293&idx=1&sn=38f6acc759df ...
- 涨知识-VI 基于TCP/UDP的应用层协议
基于TCP/UDP的应用层协议: 基于TCP: Telnet(Teletype over the Network, 网络电传),通过一个终端(terminal)登陆到网络 FTP(File Trans ...
- 涨知识 --- VI
1.空类所占空间大小 空类所占空间为1,单一继承的空类空间也为1,多继承的空类空间还是1.但是虚继承涉及虚表(虚指针),所以sizeof(C)的大小为4. 2.内联函数与宏定义 Ans:内联函数和普通 ...
- 涨知识---V
1.内存对齐 在解释内存对齐的作用前,先来看下内存对齐的规则: 1). 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数, ...
随机推荐
- ceph Luminous版手动安装零散记录
1.安装必要的依赖包,关防火墙,向/etc/hosts内添加域名等 2.安装ceph 配置yum源 (如果嫌慢,可以配置cachedir=/home/yum/$basearch/$releasever ...
- NopCommerce 更改发票字体
NopCommerce 默认是用~/App_Data/Pdf/FreeSerif.ttf 这个字体的. 用这个字体,发票里的中文不能显示. 可以把c:\windows\font\simhei.ttf ...
- rest_framework 之视图
1. 继承ModelSerilizer,直接指定要序列化的表模型 MySerializers.py from app import models # 继承ModelSerilizer,直接指定要序列化 ...
- 浮点型的三个特殊值 Double.NEGATIVE_INFINITY Double.POSITIVE_INFINITY Double.NaN
Double.NEGATIVE_INFINITY 负无穷 Double.POSITIVE_INFINITY 正无穷 Double.NaN 非数 注意:浮点数才有无穷的概念,整数是没有的 比如: int ...
- Zabbix4.0报警配置-企业微信报警
一:前期准备 1.1:企业号注册 https://qy.weixin.qq.com/ 微信调用接口说明 http://qydev.weixin.qq.com/wiki/index.php?title ...
- HTTP,RFC自学心得
HTTP协议描述的是:发送方与接收方的通信协议,通过两方的自觉遵守而存在,当然有不少的浏览器并没有百分百遵守这份协议. HTTP是运行于应用层的协议,基于TCP协议而运作.基本上是客户/服务器对答模式 ...
- My SQL随记 002 登陆
如何启动MySQL服务 Step1 我的电脑右键属性找到 控制面板 选择 系统和安全 Step2 管理工具中找到服务 Step3 找到你的MySQL启动服务 如何通过黑窗口登陆退出 MySQL Ste ...
- Delphi xe8 FMX StringGrid根据内容自适应列宽。
Delphi xe8 FMX StringGrid根据内容自适应列宽. 网上的资料比较复杂,而且不是根据字体字号等设置列宽.故自己写了个function来用. function GetColMaxDa ...
- git不添加.idea等IDE配置文件夹
git不添加.idea等IDE配置文件夹由于.idea(intellJ,pycharm)的IDE文件夹很常出现,建议将gitignore设置为全局. git config --global core. ...
- 将GETDATE()转换为指定日期格式的varchar类型
CREATE FUNCTION [dbo].[FormatDate] (@date as datetime, ) ) ) AS BEGIN ) set @datestring=@formatstrin ...