String.inter()深入理解
代码中字符串的使用对于每个程序员来说都司空见惯,大家用起来也得心应手,所以很少会花时间深入研究。但是在笔试面试中,却常常被提问,而且往往是看似熟悉的程序,却无法说出自己坚信的答案。而且今天的重点是String.inter()。今天花时间整理一下,一来自己做一个记录,二来希望帮助更多的猿类!Hahaha~
先热热身做俩道题:
Q:下列程序的输出结果:
String s1 = “abc”;
String s2 = “abc”;
System.out.println(s1 == s2);
A:true
分析一下:程序执行,常量池中生成一个字符串,并将栈中的引用指向 s1,s2 先去查询常量池中是否有已经存在,存在,则返回常量池中的引用,所以s1 = s2。
Q:下列程序的输出结果:
String s1 = new String(“abc”);
String s2 = new String(“abc”);
System.out.println(s1 == s2);
A:false,两个引用指向堆中的不同对象。
分析一下:第一步、常量池中生成一个字符串“abc”,并在堆中生成一个s1引用指向的对象,第二步、先去查询常量池中是否有已经存在“abc”,因为已经存在,所以不在生成,但堆中仍然会生成一个s2引用指向的对象,所以s1 , s2引用不一样。
Q:下列程序的输出结果:
String s1 = “abc”;
String s2 = “a”;
String s3 = “bc”;
String s4 = s2 + s3;
System.out.println(s1 == s4);
A:false,因为s2+s3实际上是使用StringBuilder.append来完成,会生成不同的对象。
分析一下:程序执行,s1,s2,s3在常量池中分别生成字符串,并将栈中的引用指向s1,s2,s3,而s4在编译的时候,其方法内部创建StringBuilder来拼接对象,在堆中生成了新的对象。
引号声明的字符串都是会直接在字符串常量池中生成的,而 new 出来的 String 对象是放在堆空间中的。
接下来好戏开始:
public static void main(String[] args) {
String str1 = "abc";
String str2 = new String("abc");
String str3 = str2.intern();
System.out.println(str1==str2);//#1
System.out.print (str1==str3);//#2
}
输出结果为: false true
#1:str1指向常量池中的对象引用,str2指向堆中的对象引用,所以返回false;
#2:str2.intern()指向str1的在常量池中的对象引用,所以str1==str3。
public static void main(String[] args) {
String abc = "abc";
final String abcFinal = "abc";
String str1 = "abc01";
String str2 = "abc"+"01";
String str3 = abc + "01";
String str4 = abcFinal+"01";
String str5 = new String("abc01").intern();
System.out.println(str1 == str2);//#3
System.out.println(str1 == str3);//#4
System.out.println(str1 == str4);//#5
System.out.println(str1 == str5);//#6
}
输出的结果为:true false true true
#3:str1指向常量池中的对象引用,而str2在编译期间,+号会自动合并为一个字符串,因为常量池中已经生成了str1的对象,所以str2不在生成,直接将常量池对象的引用赋值给栈中的str2。
#4:str4实际上是使用StringBuilder.append来完成,会生成不同的对象。
#5:final修饰的变量,在编译期间会自动进行常量替换,这是与#4不同。所以不在生成新的对象,直接将常量池对象的引用str1赋值给栈中的str4。
#6:都是指向常量池中的对象引用。
public static void main(String[] args) {
String str2 = new String("abc")+new String("01");
str2.intern();
String str1 = "abc01";
System.out.println(str2==str1);//#7
}
输出的结果为:true
#7:str2在常量池中分别生成了俩个对象,“abc”和“01”,堆中则存的是abc01的引用,并赋值给了str2,str2.intern()在常量池中生成了一个abc01的引用,并赋值给了str2,str1在生成对象之前先是查找,找到并直接返回str2在常量池中生成的引用。
public static void main(String[] args) {
String str1 = "abc01";
String str2 = new String("abc")+new String("01");
str2.intern();
System.out.println(str2 == str1);//#8
}
输出的结果为:false
#8:str1指向常量池中的对象引用,而str2指向堆中的对象引用,并在常量池生成俩个对象,“abc”和“01”,接着str2.intern()返回str1指向常量池中的对象引用,但是对于str2没有影响,结果为false,如果是str2 = str2.intern();则最终结果将是true。
上面讲了一些原理,那么为什么要使用String的intern()方法呢,甚至是非用不可??
假设有这样的一个问题,我们需要读取一个大的文件(文件中有重复的一些信息),并且要处理这些读取出来的字符串,这时候我们应该怎样编写程序才能使程序高效执行呢?
Tips:是不是首先想到用Set,HashSet来存这些字符串,回忆一下Set集合的特点,无序,不可重复。在仔细一想,无序:基于链表的数据结构,查询效率低,不方便我们处理大量的字符串;不可重复:在set值的时候,先先生成HashCode,再迭代查询是否有重复的值。。。那么有没有更好的方法呢?
intern()方法设计的初衷,就是重用String对象,以节省内存消耗。
点击打开链接
但是调用intern()方法开销也不小所以灵活运用。
String.inter()深入理解相关推荐
- Java String 常量池理解
Java String 常量池理解 String:字符串常量池 作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以 ...
- java string string_深入理解Java:String
在讲解String之前,我们先了解一下Java的内存结构. 一.Java内存模型 按照官方的说法:Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配. JVM主要管理两 ...
- c++11 string u8_深入理解C++11:C++11新
一.数据对齐 在了解为什么数据需要对齐之前,我们可以回顾一下打印结构体的大小这个C/C++中的经典案例.先看代码: #include using namespace std; struct HowMa ...
- JAVA中String.intern的理解
intern() 方法返回字符串对象的规范化表示形式. 它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern ...
- String与StringBuffer 理解
String的创建 String s = "hello"; JVM先根据内容"hello"查找对象,如果没有找到,则在heap上创建新对象,并将其赋予s1,否 ...
- public static void main(String[] args)的理解
public:权限修饰符,权限最大. static:随着MianDemo类的加载而加载,消失而消失. void: 没有返回值 main: 函数名,jvm识别的特殊函数名 (String[] args ...
- String*Buffer*Builder理解
1.String是字符串常量,StringBuffer和StringBuilder是字符串变量. 2.StringBuffer是线程安全的,StringBuilder是非线程安全的. 3.String ...
- string.intern()方法理解
String.intern()方法介绍 字符串常量池 在jdk7中,字符串常量池和静态变量都存储在堆中. 直接使用双引号声明出来的String对象会直接存储在常量池中. 如果不是用双引号声明的Stri ...
- 从自定义string类型理解右值引用
理解右值引用 前言 问题复现 自定义string(CMyString) 遇到问题 图示理解 右值引用 什么是右值 添加右值引用参数的成员方法 结果对比 解决遗留问题 前言 在之前,我写过一篇: 通过自 ...
最新文章
- 深入剖析Android系统
- python简单代码运行_python代码如何运行
- C++string容器-构造函数
- 串口通讯编程一日通3(COMMTIMEOUTS DCB整理)
- java filterinputstream_java.io.FilterInputStream.close()
- 我就是那个一直拿着死工资的人
- iframe 监听内部接口是否加载完成_低成本0基础打造自己的app之uni-app请求接口以及生命周期函数...
- spring cloud gateway 拦截request Body
- Shell笔记5——函数的知识与实践
- linux系统剪切,Linux 系统裁剪
- 潮流计算 matlab,用matlab进行潮流计算
- 怎么让电脑微信安装到别的盘路径
- 显著目标检测的研究思路
- PHP经典实例读书笔记--变量
- 今天用Java开发主机IP扫描神器,零基础Socket编程详细
- CESI: Canonicalizing Open Knowledge Bases using Embeddings and Side Information
- 2018年诺贝尔经济学奖揭晓!两位美国教授获奖
- android studio编辑环境变量,Android studio gradle环境变量配置教程
- boll指标(布林带)计算公式
- Mac系统如何查看更新R版本