夯实Java基础(五)——==与equals()
1、前言
我们在学习Java的时候,看到==、equals()就认为比较简单,随便看了一眼就过了,其实你并没有深入去了解二者的区别。这个问题在面试的时候出现的频率比较高,而且据统计有85%的人理直气壮的答错。所以理解==与equals()的区别很有必要。
2、==运算符
==可以使用在基本数据类型变量和引用数据类型变量中。
1、如果比较的是基本数据类型变量:比较两个变量的数值是否相等(数据类型不一定要相等,只看值,因为会类型自动提升!);
2、如果比较的是引用数据类型变量:比较两个对象的地址值是否相等。
下面看一下案例:
public class Test {
public static void main(String[] args) {
int a=10;
int b=10;
double c=10.00;
System.out.println(a==b);//true
System.out.println(a==c);//true
String str1="123";
String str2="123";
System.out.println(str1==str2);//true
String str3=new String("123");
String str4=new String("123");
System.out.println(str3==str4);//false
}
}
结果为:true、true、true、false。前面两个为true的结果非常容易理解,但是第三个为true,第四个为false,而它们都是String引用类型,为什么不一样呢?
分析原因:
对于8种基本数据类型(byte,short,char,int,float,double,long,boolean)的值而言,它们都是存储在常量池中,而str1、str2的字符串 "123" 也同样在常量池中,而一个常量只会对应一个地址,因此不管是再多的数据都只会存储一个地址,所以所有他们的引用都是指向的同一块地址,因此基本数据类型和String常量是可以直接通过==来直接比较的。
而str3、str4分别在堆内存中创建的两个对象,地址值自然就不相同了。
3、equals()方法
equals()是一个方法,不是数据类型,所以他只适用于引用数据类型。
该方法主要用于比较两个对象的内容是否相等。其实这样的说法是不准确的。首先我们来看看在Object类中定义的equals方法:

可以看到,在Object类型的equals方法是直接通过==来比较的,和==是没有任何区别的。
那么为什么又要说equlas和==的区别呢?是因为所有的类都直接或间接地继承自java.lang.Object类,因此我们可以通过重写equals方法来实现我们自己想要的比较方法。
我们创建一个Person类来测试,先不重写父类的equals()方法:
public class Test {
public static void main(String[] args) {
Person person1=new Person("菜徐坤",21);
Person person2=new Person("菜徐坤",21);
System.out.println(person1.equals(person2));
}
}
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
毫无疑问,输出的结果肯定是false,因为没有重写父类的equals()方法,从而调用了父类的,而父类的equals()方法是用==判断的。
然后我们重写父类的equals()方法:
public class Test {
public static void main(String[] args) {
Person person1=new Person("菜徐坤",21);
Person person2=new Person("菜徐坤",21);
System.out.println(person1.equals(person2));
}
}
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
}
重写之后输出就是true了,因为比较的对象的内容。
实际上,像String、Date、Math、File、包装类等大部分类都重写了Object的equals()方法。重写以后,就不是比较两个对象的地址值是否相同了,而是比较两个对象里面的内容是否相等。
下面我们来看一下String类重写的equals()方法:
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
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;
}
可以看到重写的方法内用char[] 数组进行一个一个的比较,并不是用==进行比较,。
我们在重写equals()方法时必须要遵循如下几个规则:
- 自反性:x.equals(x)必须返回是true。
- 对称性:如果x.equals(y),返回时true,那么y.equals(x)也必定返回为true。
- 传递性:如果x.equals(y)返回的true,而且y.equals(z)返回是true,那么z.equals(x)返回的也是true。
- 一致性:如果x.equals(y)返回是true,只要x和y的内容一直不变,不管重复x.equals(y)多少次,返回都是true
- 任何情况下,x.equals(null),永远返回是false,x.equals(与x是不同类型的对象),也永远返回是false。
对于上面几个规则,我们在使用的过程中最好遵守,避免出现意想不到的错误。
4、小结
1、==比较的数值是否相等和对象地址是否相等。
2、equals()方法比较的对象内容是否相等(前提是重写了父类的方法)。
3、一般除了自定义的类除外,大部分能够使用的类都重写了equals()方法。
夯实Java基础(五)——==与equals()的更多相关文章
- 夯实Java基础系列目录
自进入大学以来,学习的编程语言从最初的C语言.C++,到后来的Java,. NET.而在学习编程语言的同时也逐渐决定了以后自己要学习的是哪一门语言(Java).到现在为止,学习Java语言也有很长一段 ...
- 夯实Java基础系列3:一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!
目录 目录 string基础 Java String 类 创建字符串 StringDemo.java 文件代码: String基本用法 创建String对象的常用方法 String中常用的方法,用法如 ...
- 夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理
目录 final使用 final变量 final修饰基本数据类型变量和引用 final类 final关键字的知识点 final关键字的最佳实践 final的用法 关于空白final final内存分配 ...
- 夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!
目录 抽象类介绍 为什么要用抽象类 一个抽象类小故事 一个抽象类小游戏 接口介绍 接口与类相似点: 接口与类的区别: 接口特性 抽象类和接口的区别 接口的使用: 接口最佳实践:设计模式中的工厂模式 接 ...
- 夯实Java基础系列9:深入理解Class类和Object类
目录 Java中Class类及用法 Class类原理 如何获得一个Class类对象 使用Class类的对象来生成目标类的实例 Object类 类构造器public Object(); register ...
- 夯实Java基础系列13:深入理解Java中的泛型
目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试 ...
- 夯实Java基础系列14:深入理解Java枚举类
目录 初探枚举类 枚举类-语法 枚举类的具体使用 使用枚举类的注意事项 枚举类的实现原理 枚举类实战 实战一无参 实战二有一参 实战三有两参 枚举类总结 枚举 API 总结 参考文章 微信公众号 Ja ...
- 夯实Java基础(十一)——内部类
1.内部类的概念 内部类顾名思义:将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.对于很多Java初学者来说,内部类学起来真的是一头雾水,根本理解不清楚是个什么东西,包括我自己(我太菜 ...
- 夯实Java基础系列1:Java面向对象三大特性(基础篇)
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 [https://github.com/h2pl/Java-Tutorial](https: ...
- 夯实Java基础系列5:Java文件和Java包结构
目录 Java中的包概念 包的作用 package 的目录结构 设置 CLASSPATH 系统变量 常用jar包 java软件包的类型 dt.jar rt.jar *.java文件的奥秘 *.Java ...
随机推荐
- c++ 子类,基类 中this指针 虚函数使用
笔记: 子类和基类 构造函数不显式时,的this指针相同..在QT中,如果父类基于QObject,那么构造子类时传入this指针,这样所有子类,父类,基类都是同一地址.delelater(),会del ...
- HashMap原理(二) 扩容机制及存取原理
我们在上一个章节<HashMap原理(一) 概念和底层架构>中讲解了HashMap的存储数据结构以及常用的概念及变量,包括capacity容量,threshold变量和loadFactor ...
- 常用的方法论-Q12
- easyui datagrid 单元格 编辑时 事件 修改另一单元格
//datagrid 列数据 $('#acc').datagrid({ columns : [ [ { field : 'fee_lend', title : '收费A', width : 100, ...
- Tensorflow教程(2)Tensorflow的常用函数介绍
1.tf.constant tf.constant用来定义一个常量,所谓常量,广义上讲就是“不变化的量”.我们先看下官方api是如何对constant函数来定义的: tf.constant( valu ...
- Java实现LRU算法
一.LRU算法简介 LRU(Least Recently Used)最近最久未使用算法 常见应用场景:内存管理中的页面置换算法.缓存淘汰中的淘汰策略等 二.实现理论 底层结构:双向链表 + HashM ...
- 006.SQLServer AlwaysOn可用性组高可用部署
一 数据库镜像部署准备 1.1 数据库镜像支持 有关对 SQL Server 2012 中的数据库镜像的支持的信息,请参考:https://docs.microsoft.com/zh-cn/previ ...
- 判断List中是否含有某个实体bean
注意:使用List.contains(Object object)方法判断ArrayList是否包含一个元素对象(针对于对象的属性值相同,但对象地址不同的情况),如果没有重写List的元素对象Obje ...
- 跟着大彬读源码 - Redis 4 - 服务器的事件驱动有什么含义?(上)
众所周知,Redis 服务器是一个事件驱动程序.那么事件驱动对于 Redis 而言有什么含义?源码中又是如何实现事件驱动的呢?今天,我们一起来认识下 Redis 服务器的事件驱动. 对于 Redis ...
- py+appium微信公众号自动化(已搞定多个坑)
最近需要做微信公众号的自动化测试,遇到了不少坑. 微信公众号自动化与app自动化还是有区别的,因为多了不少坑.打开微信x5内核调试的就不说了,百度有. 1.首先,微信公众号有webview,uiaut ...