引言

  最近在看TIJ,看到==和equals相关内容,今天就来简单的总结下。

关系操作符==

  书中对关系操作符的描述是这样的:"关系操作符生成的是一个boolean结果,它们计算的是操作数的值之间的关系",简单的说就是比较值是否相等。下面我们通过简单的例子来体会下:

 int a=5;
int b=5;
//true
System.out.println(a==b); String str=new String("abc");
String str1=new String("abc");
String str2=new String("abc");
//false
System.out.println(str1==str2); str1=str;
str2=str;
//true
System.out.println(str1==str2);

  结果我已经在代码中标注了,下面我们来仔细看看为什么是这样?

  a==b结果为true,这个很容易理解,变量a和变量b存储的值都为5,肯定是相等的。而为什么str1和str2两次比较的结果不同?要理解这个其实只需要理解基本数据类型变量和非基本数据类型变量的区别。

  在Java中有8种基本数据类型:

  浮点型:float(4 byte), double(8 byte)

  整型:byte(1 byte), short(2 byte), int(4 byte) , long(8 byte)

  字符型: char(2 byte)

  布尔型: boolean(JVM规范没有明确规定其所占的空间大小,仅规定其只能够取字面值"true"和"false")

  对于这8种基本数据类型的变量,变量直接存储的是“值”,因此在用关系操作符==来进行比较时,比较的就是 “值” 本身。要注意浮点型和整型都是有符号类型的,而char是无符号类型的(char类型取值范围为          0~2^16-1).

  而对于非基本数据类型的变量,也称为引用类型的变量。比如上面的str、str1、str2就是引用类型的变量,引用类型的变量存储的并不是 “值”本身,而是于其关联的对象在内存中的地址。编译器在遇到new的时候一般都会在堆上分配一个对象,str、str1、str2只是存储的值是这个对象在内存中的存储地址,并不是“值”本身(即不是存储abc之类的值)。

  因此str1==str2比较时,str1和str2分别指向不同的对象,两者的内存地址当然不同。所以结果是false。

  然后代码的12、13行,将str1和str2分别设置为指向同一个对象,这样两者存储的内存地址时一样的,所以这时候结果是true。

equals方法

  equals方法是基类Object中的方法,因此对于所有的继承于Object的类都会有该方法。为了更直观地理解equals方法的作用,直接看Object类中equals方法的实现。代码如下:

 public boolean equals(Object obj) {
return (this == obj);
}

  我们看到equals方法默认是用来比较两个对象的引用是否相等,即是否指向同一个对象。那我们还是把刚才的代码稍微修改下来看一下:

 String str1=new String("abc");
String str2=new String("abc");
//true
System.out.println(str1.equals(str2));

  额,不是说equals方法比较的是否指向同一个对象吗?刚才我们上面分析过了,str1和str2指向两个不同对象,不是应该返回false吗?我们去看看String的equal方法。代码如下:

 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;
}

  可以看出,String类对equals方法进行了重写,用来比较指向的字符串对象所存储的字符串是否相等。

  其他的一些类诸如Double,Date,Integer等,都对equals方法进行了重写用来比较指向的对象所存储的内容是否相等,我们使用的时候需要注意。

简单的总结

  1)对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;

    如果作用于引用类型的变量,则比较的是所指向的对象的地址

  2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量

    如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;

    诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。

字符串驻留机制

  我们把上面的例子稍微修改下来看一下这个字符串驻留机制到底是啥?看代码:

 String str1="abc";
String str2="abc";
//true
System.out.println(str1==str2);

  操作符==比较的不是对象的地址吗?怎么会返回true不是应该false的吗?这就是字符串驻留机制的影响。

  其实过程是这样的:String对象被放进常量池里了,再次出现“abc”字符串的时候,JVM很兴奋地把str2的引用也指向了 “abc”对象,它认为自己节省了内存开销。这样str1和str2就指向了同一个对象。

  我们再来看下面这一段我们熟悉的代码:

 String str1=new String("abc");
String str2=new String("abc");
//false
System.out.println(str1==str2);

  一旦看到new,JVM就会在堆上面创建实例对象,所以这时候操作符==比较的两个对象的内存地址时不一样的。所以返回false也是在正常不过了。

  最后我们再来看一个例子:

 String str1 = "java"
String str2 = "blog";
String s = str1+str2;
//false
System.out.print(s=="javablog");

  大家也看到了结果是false。具体原因是这样的:

  JVM确实会对如String str1 = "java"; 的String对象放在字符串常量池里,但是它是在编译时刻那么做的,而String s = str1+str2; 是在运行时刻才能知道(我们当然一眼就看穿了,可是Java必须在运行时才知道的,人脑和电脑的结构不同),也就是说str1+str2是在堆里创建的, s引用当然不可能指向字符串常量池里的对象。

浅谈Java中的==和equals的更多相关文章

  1. 浅谈Java中的equals和==(转)

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...

  2. 浅谈Java中的equals和==

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...

  3. 【转】浅谈Java中的equals和==

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...

  4. 【转】浅谈Java中的hashcode方法(这个demo可以多看看)

    浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...

  5. 【转】浅谈Java中的hashcode方法

    哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native int hashCode(); 根据这个 ...

  6. 浅谈Java中的栈和堆

    人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数 ...

  7. 浅谈Java中的hashcode方法(转)

    原文链接:http://www.cnblogs.com/dolphin0520/p/3681042.html 浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地 ...

  8. 浅谈Java中set.map.List的区别

    就学习经验,浅谈Java中的Set,List,Map的区别,对JAVA的集合的理解是想对于数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),JAVA集合可以存储和操 ...

  9. Java基础学习总结(29)——浅谈Java中的Set、List、Map的区别

    就学习经验,浅谈Java中的Set,List,Map的区别,对JAVA的集合的理解是想对于数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),JAVA集合可以存储和操 ...

随机推荐

  1. webapck html-loader实现资源复用

    1.安装 npm i html-loader --save-dev 2.项目目录 layout文件夹下的footer.html文件为: <script type="text/javas ...

  2. js ==和===以及!= 和 !==的区别

    一.js == 与 === 的区别[转] 1. 对于string,number等基础类型,==和===是有区别的 1)不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型 ...

  3. How to Use Postman to Manage and Execute Your APIs

    How to Use Postman to Manage and Execute Your APIs Postman is convenient for executing APIs because ...

  4. sencha touch list(列表) item(单行)单击事件触发顺序

    测试代码如下 Ext.define('app.view.new.List', { alternateClassName: 'newList', extend: 'app.view.util.MyLis ...

  5. Linux上VNC 启动和关闭常见问题

    0, 重设密码 [root@yqrh5u2 ~]# vncpasswd           Password:          Verify:        [root@yqrh5u2 ~]# 1, ...

  6. Repository(资源库)模式

    Repository(资源库) 协调领域和数据映射层,利用类似于集合的接口来访问领域对象 定义(来自Martin Fowler的<企业应用架构模式>): Mediates between ...

  7. Rope整理(可持久化神器)

    rope是什么?STL的内置的可持久化的数组.其最为方便的就是可以O1复制原来的数组.事实上rope的内置实现也是平衡树,由于只需要复制根结点,O1可以做到复制历史版本. 然而这个东西常数特大,不开O ...

  8. Node.j中path模块对路径的操作

    一.path模块 https://nodejs.org/docs/latest/api/path.html#path_path_join_paths 1.join方法 ==> 该方法将多个参数值 ...

  9. 【CF891E】Lust 生成函数

    [CF891E]Lust 题意:给你一个长度为n的序列$a_i$,对这个序列进行k次操作,每次随机选择一个1到n的数x,令$res+=\prod\limits_{i!=x}a_i$(一开始res=0) ...

  10. github相关资料记录

    github官方配ssh api:https://help.github.com/articles/generating-ssh-keys 简书hexo静态博客搭建:http://www.jiansh ...