`
小懒蛋
  • 浏览: 31155 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

String 类型双等号操作符与intern方法

    博客分类:
  • java
阅读更多

双等号(==)操作符常常用来和equal方法比较,对于引用类型,==操作符相当于比较内存地址,同一个类型的两个实例,用==判断结果一定是false;equal方法不同对象实现不同。

然,对于String类型做如下测试代码:

String a = "abc";
String b = "abc";
System.out.println(a == b);

变量a、b是String类型的两个变量,String非基础类型,双等号判断内存地址,结果应该是false,但这段代码输出的是true。

why?

 

针对String类型双等号,equal,intren 我设计了几个case,测试报告如下:

case 1 [a-> "abc", b-> "abc"]
a==b, result is [true]
a.equals(b), result is [true]

case 2 [a-> "abc", b-> "ab" + "c"]
a==b, result is [true]
a.equals(b), result is [true]

case 3 [c-> "c", a-> "abc", b-> "ab" + c]
a==b, result is [false]
a.equals(b), result is [true]
action [String.intern]
a=b, result is [true]

case 4 [a-> "abc", b-> new String("abc")]
a==b, result is [false]
a.equals(b), result is [true]
action [String.intern]
a=b, result is [true]

 

这个测试结果是比较令我感到诧异的,有很多和我想象中不一样的地方。

1. case1 和 case2的双等号判断,都是true,这本是不同的两个对象做双等号判断,怎么会是true呢?

2. 既然case1 和case2的双等号判断是true,为什么case3 和 case4 的双等号判断又是false了呢?

3. 为什么调用了intern方法之后,原来是false的判断就编程了true了呢?

 

根据第三点可以猜测一下,intern方法应该是会把引用互相equal的却不是同一个对象的字符串对象的变量合并成指向同一个字符串对象(此句好绕口, 用英语试试? intern will make 2 different reference who refer to 2 different String object refer to 1 same string object), 因为String类型是不可变对象,所以这种处理即可节省内存空间,又不会有什么问题,因为String是不可变对象

 

java.lang.String#intern方法的非猜测解释

这是一个native的方法,虚拟机在运行时有一块内存区域叫做“运行时常量池”,常量池用来存放编译期生成的各种字面量符号引用

intern方法的作用是,如果字符串常量池中包含一个等于此String对象的字符串,则返回代表池中这个字符串的对象,否则,将此String对象好汉的字符串添加到常量池中,并返回此String对象的引用。

这样不难解释为什么原本false的结果调用过intern之后就变成了true。

 

那么现在解释一下1 和 2 两个疑问:

前面所说,常量池用来存放编译期生成的各种字面量符号引用, case1 和 case2 正好都是字面量,所以他们会被加入到常量池中,常量池中互相equal的字符串肯定是不允许存在的,所以相当于两个变量指向到了同一个对象。

什么是字面量,自行百度,其实我也是看的百度,但有一个情况需要说一下:

case 2 中 a-> "abc", b-> "ab" + "c" , b由两个字面量拼接而成,b还是字面量;

case 3 中 c-> "c", a-> "abc", b-> "ab" + c,b由一个字面量和变量c 拼接而成,b不是字面量

 

 

参考资料:1. 《深入理解JAVA虚拟机》 第二版 第二章

                  2. http://www.cnblogs.com/zdwillie/archive/2013/10/23/3384766.html

 

附录:(生成测试报告的代码)

 

public class TestString {
    public static void main(String args[]){
        Map<String, String> cases = new LinkedHashMap<String, String>();
        init(cases);
        for(Map.Entry<String, String> case_ : cases.entrySet()){
            System.out.println(String.format("case [%s]", case_.getKey()));
            test("abc", case_.getValue());
            System.out.println();
        }
    }

    private static void test(String a, String b){
        boolean result = (a==b);
        System.out.println(String.format("a==b, result is [%s]", result));
        System.out.println(String.format("a.equals(b), result is [%s]",a.equals(b)));
        if(!result){
            System.out.println("action [String.intern]");
            b = b.intern();
            System.out.println(String.format("a=b, result is [%s]", a==b));
        }
    }

    private static void init(Map<String, String> cases){
        cases.put("a-> \"abc\", b-> \"abc\"", "abc");
        cases.put("a-> \"abc\", b-> \"ab\" + \"c\"", "ab" + "c");
        String c = "c";
        cases.put("c-> \"c\", a-> \"abc\", b-> \"ab\" + c", "ab" + c);
        cases.put("a-> \"abc\", b-> new String(\"abc\")", new String("abc"));
    }
}
 

 

 

分享到:
评论

相关推荐

    String类的intern、split方法

    String类的intern、split方法 String 类的 intern 方法是一个本地方法,定义...String 类的 intern 方法和 split 方法都是非常重要的方法,它们可以帮助我们更好地处理字符串操作,避免内存的浪费,提高程序的性能。

    关于java String中intern的深入讲解

    * 提高性能:intern 方法可以提高应用程序的性能,因为它可以减少字符串对象的创建和销毁操作。 * 简化代码:intern 方法可以简化代码,因为它可以将字符串对象存储在字符串常量池中,以便重复使用相同的字符串对象...

    String.intern – 字符串池

    这篇文章将要讨论 Java 6 中是如何实现 String.intern 方法的,以及这个方法在 Java 7 以及 Java 8 中做了哪些调整。

    C#中字符串优化String.Intern、IsInterned详解

    C#中的String.Intern方法是用于将字符串添加到字符串池中的方法。字符串池是一种机制,用于存储字符串的实例,以便重复使用同一个字符串,减少内存占用。在C#中,每个字符串实例都有一个唯一的地址,通过String....

    Java 之 String 类型

    7. **String与基本类型的转换** - `Integer.parseInt(String s)`/`Double.parseDouble(String s)`:将字符串转换为整型/浮点型数值。 - `String.valueOf(int i)`/`String.valueOf(double d)`:将整型/浮点型数值...

    jdk1.8之后的String.intern()方法内存分析

    关于String.intern()方法,这个问题都被问烂了,有的文章在分析的时候还在用jdk1.7,jdk1.8之后内存模型发生了变化,内存的变化也会影响intern方法的执行,这里有必要写文章分析一下,请大家务必从头开始看,这样...

    深入理解JavaString#intern()内存模型Ja

    在Java编程语言中,`String`类是极其重要的,它提供了许多用于操作字符串的方法,其中之一便是`intern()`。深入理解`String#intern()`方法对于优化内存使用和理解Java的内存模型至关重要。`intern()`方法是一个非常...

    string常量池和intern_韩雅茹Java系列2021.pdf

    如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。 在Java中,字符串常量池存在于方法区中。方法...

    Java String的intern用法解析

    Java String的intern方法是Java中一个非常重要的方法,它可以将字符串常量池中的字符串对象返回给我们。今天,我们将深入探究Java String的intern用法解析,了解它的工作原理和应用场景。 Java String的intern方法 ...

    java String的intern方法

    Java中的`String`类的`intern()`方法是一个非常有趣且重要的功能,它涉及到字符串的内存管理,特别是字符串常量池。常量池是Java虚拟机(JVM)的一部分,存储预编译的字符串字面量和其他常量。`intern()`方法的作用...

    深入理解 Java String#intern() 内存模型.docx

    Java String#intern() 内存模型是 Java 语言中一个重要的概念,.string#intern() 方法是 Java 字符串常量池中一个重要的组件。字符串常量池是一个固定大小的 HashMap,桶的数量默认是 1009,从 Java7u40 开始,该...

    解析Java中的String对象的数据类型 字符串

    最后,需要破除一个错误的理解,即使用String.intern()方法不能将一个String对象保存到一个全局String表中。如果具有相同值的Unicode字符串已经在这个表中,那么String.intern()方法将返回该表中的字符串常量的引用...

    String类简介

    **六、String与基本类型的转换** 1. `Integer.toString(int i)` 和 `Integer.parseInt(String s)`: 整型与字符串的转换。 2. `Double.parseDouble(String s)` 和 `Double.toString(double d)`: 浮点型与字符串的转换...

    JVM系列之String.intern的性能解析

    之前我们提到了,String.intern方法会返回字符串常量池中的字符串对象的引用。 而G1垃圾回收器的字符串去重的功能其实和String.intern有点不一样,G1是让两个字符串的底层指向同一个byte[]数组。 有图为证: 上图中...

    String常用方法练习

    你可以使用双引号初始化,如`String str = "Hello"`,或使用`new String()`构造函数。 2. **字符串比较** 使用`equals()`方法进行内容比较,`==`则比较对象引用。例如,`str1.equals(str2)`比较字符串内容,`str1 ...

    String创建对象

    `String`类的`intern()`方法用于获取常量池中的字符串引用。如果常量池中已存在该字符串,则返回其引用;否则,将字符串添加到常量池并返回引用。例如: ```java String str4 = new String("Hello").intern(); //...

    不同jdk版本下对String的intern()的分析.pos

    pos文件是ProcessOn的源文件,可以导入后直接打开编辑。 内容是:不同jdk版本下对String的intern()的分析

Global site tag (gtag.js) - Google Analytics