代码中字符串的使用对于每个程序员来说都司空见惯,大家用起来也得心应手,所以很少会花时间深入研究。但是在笔试面试中,却常常被提问,而且往往是看似熟悉的程序,却无法说出自己坚信的答案。而且今天的重点是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()深入理解相关推荐

  1. Java String 常量池理解

    Java String 常量池理解 String:字符串常量池 作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以 ...

  2. java string string_深入理解Java:String

    在讲解String之前,我们先了解一下Java的内存结构. 一.Java内存模型 按照官方的说法:Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配. JVM主要管理两 ...

  3. c++11 string u8_深入理解C++11:C++11新

    一.数据对齐 在了解为什么数据需要对齐之前,我们可以回顾一下打印结构体的大小这个C/C++中的经典案例.先看代码: #include using namespace std; struct HowMa ...

  4. JAVA中String.intern的理解

    intern() 方法返回字符串对象的规范化表示形式. 它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern ...

  5. String与StringBuffer 理解

    String的创建 String s = "hello";  JVM先根据内容"hello"查找对象,如果没有找到,则在heap上创建新对象,并将其赋予s1,否 ...

  6. public static void main(String[] args)的理解

    public:权限修饰符,权限最大. static:随着MianDemo类的加载而加载,消失而消失. void:  没有返回值 main: 函数名,jvm识别的特殊函数名 (String[] args ...

  7. String*Buffer*Builder理解

    1.String是字符串常量,StringBuffer和StringBuilder是字符串变量. 2.StringBuffer是线程安全的,StringBuilder是非线程安全的. 3.String ...

  8. string.intern()方法理解

    String.intern()方法介绍 字符串常量池 在jdk7中,字符串常量池和静态变量都存储在堆中. 直接使用双引号声明出来的String对象会直接存储在常量池中. 如果不是用双引号声明的Stri ...

  9. 从自定义string类型理解右值引用

    理解右值引用 前言 问题复现 自定义string(CMyString) 遇到问题 图示理解 右值引用 什么是右值 添加右值引用参数的成员方法 结果对比 解决遗留问题 前言 在之前,我写过一篇: 通过自 ...

最新文章

  1. 深入剖析Android系统
  2. python简单代码运行_python代码如何运行
  3. C++string容器-构造函数
  4. 串口通讯编程一日通3(COMMTIMEOUTS DCB整理)
  5. java filterinputstream_java.io.FilterInputStream.close()
  6. 我就是那个一直拿着死工资的人
  7. iframe 监听内部接口是否加载完成_低成本0基础打造自己的app之uni-app请求接口以及生命周期函数...
  8. spring cloud gateway 拦截request Body
  9. Shell笔记5——函数的知识与实践
  10. linux系统剪切,Linux 系统裁剪
  11. 潮流计算 matlab,用matlab进行潮流计算
  12. 怎么让电脑微信安装到别的盘路径
  13. 显著目标检测的研究思路
  14. PHP经典实例读书笔记--变量
  15. 今天用Java开发主机IP扫描神器,零基础Socket编程详细
  16. CESI: Canonicalizing Open Knowledge Bases using Embeddings and Side Information
  17. 2018年诺贝尔经济学奖揭晓!两位美国教授获奖
  18. android studio编辑环境变量,Android studio gradle环境变量配置教程
  19. boll指标(布林带)计算公式
  20. Mac系统如何查看更新R版本

热门文章

  1. Excel 制作散点图并添加趋势线
  2. 如何用PADS建立元件封装
  3. python编写聊天刷屏代码【非程序】
  4. 文津读书沙龙:吴军杨早数学之美-文明之光
  5. altera DCFIFO IP核 功能仿真
  6. Canfestival对象字典工具objdictedit运行环境配置
  7. 《啊哈C语言》第四章第六节习题2
  8. 不惜一切、背负责任:王怀南用八个字掀开宝宝树新篇章
  9. PS新建文档Ctrl+N
  10. matlab卷积相关