http://904582819.blog.163.com/blog/static/11159282020127794456840/
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应用都可以建立在此基础上来进行分析。
- java 创建string对象机制 字符串缓冲池 字符串拼接机制
对于创建String对象的机制,在这一过程中涉及的东西还是值得探究一番的. 首先看通过new String对象和直接赋值的方式有什么区别,看如下代码: public static void main( ...
- 【Java基础】JAVA不可变类(immutable)机制与String的不可变性
一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String(8种基本数据类型的包装类和S ...
- string 驻留机制
string 驻留机制 string s1 = "abc"; string s2 = "ab"; string s3 = s2 + "c" ...
- 【原创】Java和C#下String类型中的==和equals的原理与区别
一.Java下 1.几个例子 public static void main(String[] arge) { String str1 = new String("1234"); ...
- 深入解析字符串的比较方法:“==”操作符;String.Equals方法;String.Compare方法;String.CompareOrdinal方法。
1:要判断2个字符串变量是否相等,最高效的方法是看它们是否指向相同的内存地址.前面使用RefernceEquals方法来比较.如果2个变量指向的是不同的内存地址,那么就需要逐字符的比较2个字符串的变量 ...
- Java String 的equals, == , hascode的区别
1.equals 和 == ==在java中是比较引用的,即在内存中的地址.而String的equals()是比较字符串的内容 http://blog.csdn.net/barryhappy/arti ...
- C#基础知识之字符串比较方法:“==”操作符;RefernceEquals;String.Equals方法;String.Compare方法;String.CompareOrdinal方法。
一.“==”操作符:String.Equals:ReferenceEquals 方法 1.在编程中实际上我们只需要这两种比较,c#中类型也就这两种 (1)值类型的比较:一般我们就是判断两个值类型实例各 ...
- JAVA不可变类(immutable)机制与String的不可变性--非常好.
JAVA不可变类(immutable)机制与String的不可变性 https://www.cnblogs.com/jaylon/p/5721571.html
- java 创建string对象机制 字符串缓冲池 字符串拼接机制 字符串中intern()方法
字符串常量池:字符串常量池在方法区中 为了优化空间,为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池.如果字符串已经存在池中,就 ...
随机推荐
- 关于HTML5音频——audio标签和Web Audio API各平台浏览器的支持情况
对比audio标签 和 Web Audio API 各平台浏览器的支持情况: audio element Web Audio API desktop browsers Chrome 14 Yes ...
- 程序设计入门——C语言 第6周编程练习 1 分解质因数(5分)
1 分解质因数(5分) 题目内容: 每个非素数(合数)都可以写成几个素数(也可称为质数)相乘的形式,这几个素数就都叫做这个合数的质因数.比如,6可以被分解为2x3,而24可以被分解为2x2x2x3. ...
- iOS 开发遇到的问题之(nil指针对NSDictionary及NSArray初始化的影响)
nil指针对NSDictionary及NSArray初始化的影响 最近在做项目的时候遇到一个挺坑的崩溃问题,是由于NSDictionary初始化时nil指针引起的崩溃.假设我们现在要初始化一个{key ...
- oracle 存储过程创建及执行简单实例
1. 创建 CREATE OR REPLACE PROCEDURE getAplage(eNo IN NUMBER,salary OUT NUMBER) AS BEGIN SELECT AplAge ...
- ant 错误 Specified VM install not found: type Standard VM, name jdk1.6.0_27
ant 错误 ant Specified VM install not found: type Standard VM, name jdk1.6.0_27 原因: 安装了新的jdk, 在workspa ...
- Tomcat APR & Linux Optimization
一.简介 APR(Apache portable Run-time libraries)模式:简单理解,就是从操作系统级别解决异步IO问题,大幅度的提高服务器的处理和响应性能, 也是Tomcat运行高 ...
- jQuery Mobile学习日记之HelloWorld
这里是本人学习jQuery Mobile的过程,主要用于记录,过程中有不对的地方或不严谨的地方,欢予以指出纠正,非常感谢! 1.首先是下载安装以下文件: [Opera Mobile Emulator] ...
- JavaScipt 样式操作
我们知道HTML样式定义的三种方式: <link/>外部引入也就是定义 CSS 中的 <style/>嵌入式样式 style特性地定义 给一个HTML元素设置css属性,如: ...
- 未能加载文件或程序集“Newtonsoft.Json”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配
引用第三方的 fineui 库依然使用旧版本导致.更换 fineui为新版,或找到源码更改引用 为新版,问题解决.
- Mongodb 副本集分片(一)---初始化mongodb安装启动
写在前面:mongodb是nosql非关系型数据库中,比较受欢迎的产品.在数据持久化及与关系型数据库的关联上也做的比较好,目前各大公司在存放二进制文件(图片.视频等)中应用也比较广泛.其遵循的key- ...