equals方法和==的区别
首先大家知道,String既可以作为一个对象来使用,又可以作为一个基本类型来使用。这里指的作为一个基本类型来使用只是指使用方法上的,比如String s = "Hello",它的使用方法如同基本类型int一样,比如int i = 1;,而作为一个对象来使用,则是指通过new关键字来创建一个新对象,比如String s = new String("Hello")。但是它的内部动作其实还是创建了一个对象,这点稍后会说到。
其次,对String对象的比较方法需要了解。Java里对象之间的比较有两种概念,这里拿String对象来说:一种是用"=="来比较,这种比较是针对两个String类型的变量的引用,也就是说如果两个String类型的变量,它们所引用同一个String对象(即指向同一块内存堆),则"=="比较的结果是true。另一种是用Object对象的equals()方法来比较,String对象继承自Object,并且对equals()方法进行了重写。两个String对象通过equals()方法来进行比较时,其实就是对String对象所封装的字符串内容进行比较,也就是说如果两个String对象所封装的字符串内容相同(包括大小写相同),则equals()方法将返回true。
现在开始将对String对象的创建做具体的分析:
1、/////////////////////////////////////////////////////////////////////////
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
false
true
这个结果相信大家很好理解,两个String类型的变量s1和s2都通过new关键字分别创建了一个新的String对象,这个new关键字为创建的每个对象分配一块新的、独立的内存堆。因此当通过"=="来比较它们所引用的是否是同一个对象时,将返回false。而通过equals()方法来比较时,则返回true,因为这两个对象所封装的字符串内容是完全相同的。
2、//////////////////////////////////////////////////////////////////////////////////
String s1 = new String("Hello");
String s2 = s1;
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
true
true
这个结果应该更好理解,变量s1还是通过new关键字来创建了一个新的String对象,但这里s2并没有通过new关键字来创建一个新的String对象,而是直接把s1赋值给了s2,即把s1的引用赋值给了s2,所以s2所引用的对象其实就是s1所引用的对象。所以通过"=="来比较时,返回true。既然它们引用的都是同一个对象,那么通过equals()方法来比较时,肯定也返回true,这里equals()方法其实在对同一个对象进行比较,自己肯定等于自己咯。
3、//////////////////////////////////////////////////////////////////////////////
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
true
true
为什么这个结果?那么来分析一下。首先这两个String对象都是作为一个基本类型来使用的,而不是通过new关键字来创建的,因此虚拟机不会为这两个String对象分配新的内存堆,而是到String缓冲池中来寻找。
首先为s1寻找String缓冲池内是否有与"Hello"相同值的String对象存在,此时String缓冲池内是空的,没有相同值的String对象存在,所以虚拟机会在String缓冲池内创建此String对象,其动作就是new String("Hello");。然后把此String对象的引用赋值给s1。
接着为s2寻找String缓冲池内是否有与"Hello"相同值的String对象存在,此时虚拟机找到了一个与其相同值的String对象,这个String对象其实就是为s1所创建的String对象。既然找到了一个相同值的对象,那么虚拟机就不在为此创建一个新的String对象,而是直接把存在的String对象的引用赋值给s2。
这里既然s1和s2所引用的是同一个String对象,即自己等于自己,所以以上两种比较方法都返回ture。
到这里,对String对象的基本概念应该都已经理解了。现在我来小结一下:
针对String作为一个基本类型来使用:
1。如果String作为一个基本类型来使用,那么我们视此String对象是String缓冲池所拥有的。
2。如果String作为一个基本类型来使用,并且此时String缓冲池内不存在与其指定值相同的String对象,那么此时虚拟机将为此创建新的String对象,并存放在String缓冲池内。
3。如果String作为一个基本类型来使用,并且此时String缓冲池内存在与其指定值相同的String对象,那么此时虚拟机将不为此创建新的String对象,而直接返回已存在的String对象的引用。
针对String作为一个对象来使用:
1。如果String作为一个对象来使用,那么虚拟机将为此创建一个新的String对象,即为此对象分配一块新的内存堆,并且它并不是String缓冲池所拥有的,即它是独立的。
理解了以上内容后,请看以下代码段:
4、/////////////////////////////////////////////////////////////////////////////
String s1 = "Hello";
String s2 = new String("Hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
false
true
根据上面的小结来进行分析。第一行是把String作为一个基本类型来使用的,因此s1所引用的对象是属于String缓冲池内的。并且此时String缓冲池内并没有与其值相同的String对象存在,因此虚拟机会为此创建一个新的String对象,即new String("Hello");。第二行是把String作为一个对象来使用的,因此s2所引用的对象不属于String缓冲池内的,即它是独立的。通过new关键字,虚拟机会为此创建一个新的String对象,即为它分配了一块新的内存堆。因此"=="比较后的结果是false,因为s1和s2所引用的并不是同一个对象,它们是独立存在的。而equals()方法所返回的是true,因为这两个对象所封装的字符串内容是完全相同的。
现在,相信大家已经完全搞清楚String对象是怎么一回事了:)但是到此并没有结束,因为String对象还有更深层次的应用。
这里我将分析一下String对象的intern()方法的应用:
intern()方法将返回一个字符串对象的规范表示法,即一个同该字符串内容相同的字符串,但是来自于唯一字符串的String缓冲池。这听起来有点拗口,其实它的机制有如以下代码段:
String s = new String("Hello");
s = s.intern();
以上代码段的功能实现可以简单的看成如下代码段:
String s = "Hello";
你一定又开始疑惑了?那么你可以先看第二个代码段。第二个代码段的意思就是从String缓冲池内取出一个与其值相同的String对象的引用赋值给s。如果String缓冲池内没有与其相同值的String对象存在,则在其内为此创建一个新的String对象。那么第一段代码的意思又是什么呢?我们知道通过new关键字所创建出的对象,虚拟机会为它分配一块新的内存堆。如果平凡地创建相同内容的对象,虚拟机同样会为此分配许多新的内存堆,虽然它们的内容是完全相同的。拿String对象来说,如果连续创建10个相同内容的String对象(new String("Hello")),那么虚拟机将为此分配10块独立的内存堆。假设所创建的String对象的字符串内容十分大,假设一个Stirng对象封装了1M大小的字符串内容,那么如果我们创建10个此相同String对象的话,我们将会毫无意义的浪费9M的内存空间。我们知道String是final类,它所封装的是字符串常量,因此String对象在创建后其内部(字符串)值不能改变,也因此String对象可以被共享。所以对于刚才提到的假设,我们所创建的10个相同内容的String对象,其实我们只需为此创建一个String对象,然后被其它String变量所共享。要实现这种机制,唯一的、简单的方法就是使用String缓冲池,因为String缓冲池内不会存在相同内容的String对象。而intern()方法就是使用这种机制的途径。在一个已实例化的String对象上调用intern()方法后,虚拟机会在String缓冲池内寻找与此Stirng对象所封装的字符串内容相同值的String对象,然后把引用赋值给引用原来的那个String对象的String类型变量。如果String缓冲池内没有与此String对象所封装的字符串内容相同值的String对象存在,那么虚拟机会为此创建一个新的String对象,并把其引用赋值给引用原来的那个String对象的String类型变量。这样就达到了共享同一个String对象的目的,而原先那个通过new关键字所创建出的String对象将被抛弃并被垃圾回收器回收掉。这样不但降低了内存的使用消耗,提高了性能,而且在String对象的比较上也同样更方便了,因为相同的String对象将被共享,所以要判断两个String对象是否相同,则只需要使用"=="来比较,而无需再使用equals()方法来比较,这样不但使用起来更方便,而且也提高了性能,因为String对象的equals()方法将会对字符串内容拆解,然后逐个进行比较,如果字符串内容十分大的话,那么这个比较动作则大大降低了性能。
说到此,大家可能对具体应用还有点模糊,那么我来举个简单的示例,以便阐述以上概念:
假设有一个类,它有一个记录消息的方法,这个方法记录用户传来的消息(假设消息内容可能较大,并且重复率较高),并且把消息按接收顺序记录在一个列表中。我想有些朋友会这样设计:
import java.util.*;
public class Messages {
ArrayList messages = new ArrayList();
public void record(String msg) {
messages.add(msg);
}
public List getMessages() {
return messages;
}
}
这种设计方案好吗?假设我们重复的发送给record()方法同一个消息(消息来自不同的用户,所以可以视每个消息为一个new String("...")),并且消息内容较大,那么这个设计将会大大浪费内存空间,因为消息列表中记录的都是新创建的、独立的String对象,虽然它们的内容都相同。那么怎么样可以对其进行优化呢,其实很简单,请看如下优化后的示例:
import java.util.*;
public class Messages {
ArrayList messages = new ArrayList();
public void record(String msg) {
messages.add(msg.intern());
}
public List getMessages() {
return messages;
}
}
正如你所看到的,原先record()方法中的messages.add(msg);代码段变成了messages.add(msg.intern());,仅仅对msg参数调用了intern()方法,这样将对重复的消息进行共享机制,从而降低了内存消耗,提高了性能。
这个例子的确有点牵强,但是这里只是为了阐述以上概念!
至此,String对象的迷雾都被消除了,大家只要牢记这些概念,以后再复杂的String应用都可以建立在此基础上来进行分析。
public class stringequals {
public static void main(String[] args) {
String s= "hello";
String t = "hello";
char c[] = {'h','e','l','l','o'} ;
System.out.println(s.equals(t));
System.out.println( t.equals(c));
System.out.println(s==t);
System.out.println(t.equals(new String("hello")));
System.out.println("-----可爱的分割线-------");
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
}
}
true
false
true
true
-----可爱的分割线-------
false
true
- String的equals方法和==
String类的对象是字符串常量,一切看起来改变了String对象的操作,其实只是改变了字符串引用变量所引用的字符串罢了. Java中的字符串存放在一个公共的存储池中,引用指向存储池中相应的位置,编译 ...
- String的equals()方法源码解析
每个String对象在创建的时候都构造了一个char类型的final声明的不可替换数组,数组中的每一个元素即字符串对应的每一个字符如图: String的equals()在比较的时候会进行两步比较: 1 ...
- JAVA学习(二) String使用equals方法和==分别比较的是什么?(转)
String使用的equals方法和==的区别 equals方法和==的区别 首先大家知道,String既可以作为一个对象来使用,又可以作为一个基本类型来使用.这里指的作为一个基本类型来使用只是指 ...
- 关于String的equals问题和StringBuilder问题
今天弄了一下String和StringBuilder,遇到了一些问题. 老规矩上代码图片: 发现stringBuilder的equals方法有问题,看了一下源码,发现stringbuilder没有重写 ...
- java提高篇(十三)-----equals()方法总结
equals() 超类Object中有这个equals()方法,该方法主要用于比较两个对象是否相等.该方法的源码如下: public boolean equals(Object obj) { retu ...
- java10-3 equals方法
public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”. 该方法,默认情况下比较的是地址值.但是,如果只是比较地址值的话,一般来说意义不大,所以要 ...
- JAVA面试题:equals()方法和== 区别
http://bbs.csdn.net/topics/390000725 总结: equals在没重写之前和==一样,重写之后,equals只要内容一样即为true equals跟==一般情况下是等价 ...
- Java String 的equals, == , hascode的区别
1.equals 和 == ==在java中是比较引用的,即在内存中的地址.而String的equals()是比较字符串的内容 http://blog.csdn.net/barryhappy/arti ...
- 深入分析Java的String类的方法与特点
字符串是任何编程语言都必须支持的变量类型,有些编程语言是直接提供了原生的变量类型,有些编程语言则使用语法特性以 SDK 的形式提供支持.在Java编程平台中,对字符串的支持使用了后者的形式,就是通过在 ...
随机推荐
- iOS开发中提交带有中文或特殊字符串的参数
iOS开发中,与后台进行数据交换是一个很常见的场景. 在web开发中,对于我们提交的地址,浏览器会负责进行decode,但是在ios中,必须要自己手动来实现.否则我们拼接出的网址在包括中文.特殊字符串 ...
- NopCommerce架构分析之五------Model绑定Action参数
asp.net MVC中Action参数不只是一些基本类型,也支持实体参数.那么从客户端传来的数据如何映射或转换成实体对象呢?就是通过实体绑定类ModelBinder.此系列类在请求转化为后台Cont ...
- create Context Menu in Windows Forms application using C# z
In this article let us see how to create Context Menu in Windows Forms application using C# Introduc ...
- bindService和startService的区别
区别: startService,关闭服务退出activity,service仍然处于后台运行 bindService,关闭服务退出activity直接stopService,停止服务 bindSer ...
- (二)GameMaker:Studio ——使用等高图生成3D地形
上一篇,我们讲解了GM中导入模型的方法,这节我们来讲地形. 源文件地址:http://pan.baidu.com/share/link?shareid=685772423&uk=2466343 ...
- 利用过采样技术提高ADC测量微弱信号时的分辨率
1. 引言 随着科学技术的发展,人们对宏观和微观世界逐步了解,越来越多领域(物理学.化学.天文学.军事雷达.地震学.生物医学等)的微弱信号需要被检测,例如:弱磁.弱光.微震动.小位移.心电.脑电等[1 ...
- NOIP2011 Mayan游戏
3 Mayan游戏 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上 ...
- 用Python写的批量文件重命名
有些时候下载图片或其他文件,文件名都怪怪的,可选的办法是下载一个文件批量重命名的软件.当然,如果想自己'DIY'一把的话编个Python脚本最好不过了. 下面的代码实现的对指定类型的文件进行批量重 ...
- DLLImport
namespace Wintellect.Interop.Sound { using System; using System.Runtime.InteropServices; using Syste ...
- 恒天云IaaS基础设施标准
系统总体要求: 支持多种操作系统:支持Windows,Redhat.Suse等Linux操作系统: 支持多种虚拟化系统:支持多种计算资源虚拟化方式: 网络接口:支持千兆及万兆以太网技术: 供电:支持直 ...