关于一段有趣代码引出的String创建对象的解释
通常来说,我们认为hashCode不相同就为不同的对象。就这样由一段代码引发了一场讨论,代码如下:
@Test
public void stringCompare() {
String s1 = "test";
String s2 = "test";
String s3 = new String("test");
String s4 = new String("test"); System.out.println("value compare:");
System.out.println("s1.equals(s2):" + s1.equals(s2));
System.out.println("s2.equals(s3):" + s2.equals(s3));
System.out.println("s3.equals(s4):" + s3.equals(s4));
System.out.println("s1==s2:" + (s1 == s2));
System.out.println("s2==s3:" + (s2 == s3));
System.out.println("s3==s4:" + (s3 == s4)); System.out.println("hashCode compare:");
System.out.println("s1~s2:"+ (s1.hashCode() == s2.hashCode()));
System.out.println("s2~s3:"+ (s2.hashCode() == s3.hashCode()));
System.out.println("s3~s4:"+ (s3.hashCode() == s4.hashCode()));
}
有兴趣的话先猜一猜上面的打印结果。这段代码可以很好的说明String在创建对象的特殊性。
运行上面的代码结果为:
value compare:
s1.equals(s2):true
s2.equals(s3):true
s3.equals(s4):true
s1==s2:true
s2==s3:false
s3==s4:false
hashCode compare:
s1~s2:true
s2~s3:true
s3~s4:true
猜对了吗?会不会有点奇怪,接下来我将逐一说明,并解释String创建对象的机理。
首先我们知道equals的比较是两个对象的值是否相同,这个毋庸置疑,我们都赋值“test”,所以结果必然是三个true,这一点没有什么问题。
然后看“==”的比较,“==”是比较物理地址时候相同,也是比较是否为同一对象的手段。结果是s1和s2是true,后面的两个比较是false,这就说明s1和s2指向的是同一块地址。s3和s4是通过new出来的对象,我们知道new通常是开辟了新空间,而直接赋值是引用赋值。所以这一点也基本上没有什么问题,这就解释了s2==s3:false,s3==s4:false。
最后同通常我们认为hashCode不同就是不同的对象,但是这四个对象的hashCode是全部相同的。这似乎和使用"=="比较有点违背。但其实并不矛盾,必须明确一点是hashCode和物理地址没有必然的关系。之所以是这样,是因为Sting在创建对象时的机制有所不同。
重点:
JVM为String类型提供了一个字符池(jdk7之前在permgen,jdk7之后也是堆里)。每次在创建对象时,都会现在字符池中查找该字符串是否存在。这是大的前提逻辑,现在我们就一下几种情况分别说明:
1.创建一个对象 String s1 = new String("我是字符串"),遵循大逻辑,先在pool中检索,但其实无论pool中有没有,都会创建一个新的对象。不同的是:
a.pool中没有:
在pool中添加一个新的对象“我是字符串”,也就是说这里创建了两个对象,除了s1这个对象外,在pool中还创建了一个对象;这个时候创建s2 = "我是字符串"; 同样检查pool,发现已有,那s2指向pool中的“我是字符串”的地址。
b.pool中有:
则只创建一个对象及就是s1。这个时候创建s2= “我是字符串”;同样会检查pool发现存在,那s2直接指向pool中的地址。
2.创建一个String s1 = "我是字符串",遵循大逻辑,先在pool中检索:
a.pool中没有:
在pool中没有检索到“我是字符串”,那么在pool中添加一个字符串对象“我是字符串”,然后s1指向pool中的地址。这个时候如果创建String s2 = new String("我是字符串");检测pool中已有,同1.b中创建s1过程。
b.pool中有:
在pool中检索到,s1直接指向pool中的地址,如果创建String s2 = new String("我是字符串");同1.b中创建s1过程。
注意:
1.hashCode实际与物理地址没有必然关系,只是习惯上我们可以用hashCode判断是否为同一对象。
2.pool也是有大小限制的,对于不用的字符串对象,垃圾机器人会回收,释放空间。
关于一段有趣代码引出的String创建对象的解释的更多相关文章
- 一段C++代码想到的问题
今天在学习<Unix环境高级编程>,第七章进程环境给出了一个进程的内存分布示意图,从下往上依次为“正文段->初始化数据->未初始化数据(默认初始化为0)->堆(从低地址到 ...
- 通过Java字节码发现有趣的内幕之String篇(上)(转)
原文出处: jaffa 很多时候我们在编写Java代码时,判断和猜测代码问题时主要是通过运行结果来得到答案,本博文主要是想通过Java字节码的方式来进一步求证我们已知的东西.这里没有对Java字节码知 ...
- c#代码 天气接口 一分钟搞懂你的博客为什么没人看 看完python这段爬虫代码,java流泪了c#沉默了 图片二进制转换与存入数据库相关 C#7.0--引用返回值和引用局部变量 JS直接调用C#后台方法(ajax调用) Linq To Json SqlServer 递归查询
天气预报的程序.程序并不难. 看到这个需求第一个想法就是只要找到合适天气预报接口一切都是小意思,说干就干,立马跟学生沟通价格. 不过谈报价的过程中,差点没让我一口老血喷键盘上,话说我们程序猿的人 ...
- java如何从一段html代码中获取图片的src路径
java如何从一段html代码中获取图片的src路径 package com.cellstrain.icell.Test; import java.util.ArrayList;import java ...
- 一段小代码秒懂C++右值引用和RVO(返回值优化)的误区
关于C++右值引用的参考文档里面有明确提到,右值引用可以延长临时变量的周期.如: std::string&& r3 = s1 + s1; // okay: rvalue referen ...
- C# 一段绘图代码 在form_load事件不能显示图
今天无意将一段绘图代码 写在form_load事件了,结果不能显示绘图.(代码:Graphics g = this.CreateGraphics();Pen pen = new Pen(Color.R ...
- 【转】可执行程序包括BSS段、数据段、代码段
可执行程序包括BSS段.数据段.代码段(也称文本段). 一.BSS BSS(Block Started by Symbol)通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域.特点是:可 ...
- 五个数据段之代码段、数据段、BSS、栈、堆
继上文讲完了对内存管理的一些知识,下面笔者再对上篇文章的内容加以拓展,那么我们今天就来说一说5个数据段 五个数据段 进程(执行的程序)会占用一定数量的内存,它或是用来存放磁盘载入的程序代码,或是存放取 ...
- 数据段、代码段、堆栈段、BSS段的区别
进程(执行的程序)会占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用 途 不一而不尽相同,有些内存是事先静态分配和统一回收的 ...
随机推荐
- spring多个context:property-placeholder不生效问题
先来看下A和B两个模块,A模块和B模块都分别拥有自己的Spring XML配置,并分别拥有自己的配置文件: A模块的Spring配置文件如下: <?xml version="1.0&q ...
- 百度网盘SVIP不限速Mac破解版(亲测可用)
百度网盘SVIP不限速Mac破解版(亲测可用),按照教程一步一步来就可以了,链接如下: https://mac.orsoon.com/Mac/166358.html?id=ODY0MDA2Jl8mMT ...
- JavaEE高级-JPA学习笔记
*JPA概述 *JPA是什么? - Java Persistence API :用于对象持久化的API - Java EE 5.0平台标准的ORM规范,使得应用程序以统一的方式访问持久化层 - JPA ...
- 05-转置-置换-向量空间R
一.置换矩阵 一个矩阵的行或者列交换,可以借助另外一个矩阵相乘来实现 首先是行交换: $\underbrace{\left[\begin{array}{ccc}{1} & {1} & ...
- 10年前文章_ vi编辑器查找与替换方法
vi编辑器查找与替换方法1.查找:/ 当前行往下找:? 当前行往上找找到后继续查找同方向 n反方向 N2.替换格式: range s/source/target/g解释:range表示要搜索的范围 & ...
- C#基础知识之扩展方法
扩展方法需要满足的条件: 1.扩展方法必须定义在静态类里. 2.扩展方法必须是静态方法. 3.扩展方法的第一个参数以this修饰符为前缀. 4.扩展方法必须在使用它的类的扩展方法内,否则必须显示的us ...
- 如何在vue中引入图片?
当我们在Vue.js项目中引用图片时,关于图片路径有以下几种情形: 使用一. 我们在data里面定义好图片路径 imgUrl:'../assets/logo.png' 然后,在template模板里面 ...
- linux软件操作
操作 命令 ubuntu 源操作 源配置 https://www.cnblogs.com/wenlin-gk/p/11146228.html 源更新 sudo apt-get update 查看源中包 ...
- Ansible环境搭建
Installation Guide(Ansible官网链接) Basics / What Will Be Installed What Version To Pick? Control Machin ...
- jquery每次动态加载dom,绑定事件会多一次,
jquery绑定事件,每次动态加载dom,绑定的事件会加1,比如动态加载dom5次,点那个点击事件会弹出5次 解决办法就是在每次绑定之前解绑定. $('.seek-footer .btn1').off ...