欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

String用于提升性能的intern()方法

程序员文章站 2022-05-18 17:49:04
JDK每次升级都会做很多优化,我们使用最多的String常量类也在不断被优化。这次和大家分享的是String优化手段之一的intern()方法。源码API如下:/*** Returns a canonical representation for the string object.* * A pool of strings, initially empty, is maintained privately by the* class {@code String}.* * When th...

JDK每次升级都会做很多优化,我们使用最多的String常量类也在不断被优化。这次和大家分享的是JDK1.8中对String的优化之一,intern()方法的使用。


对应的方法及注释如下:

/**
* Returns a canonical representation for the string object.
*


* A pool of strings, initially empty, is maintained privately by the
* class {@code String}.
*


* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
*


* It follows that for any two strings {@code s} and {@code t},
* {@code s.intern() == t.intern()} is {@code true}
* if and only if {@code s.equals(t)} is {@code true}.
*


* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
* The Java™ Language Specification.
*
* @return a string that has the same contents as this string, but is
* guaranteed to be from a pool of unique strings.
*/
public native String intern();

一句话概括,就是通过常量池复用来节省内存空间、减少开销以提升性能。

Tips:

这里简单介绍一下常量池,方便下文理解。先看看JVM的内存结构:
String用于提升性能的intern()方法
我们的常量池就在方法区中,在实际应用中会跟堆区配合使用。平时大家都统称它为常量池,严格划分的话常量池又分为:静态常量池、运行时常量池和字符串常量池。三者的区别,有时间会写一篇单独的博客。


回到今天的主题,intern()方法。如果我们对着英文注释一句一句翻译,来理解它的话会很有限很苦涩,结合代码示例理解会更好一些(个人经验)。

示例一:

public static void main(String[] args) {

        String str1 = "abc";
        String str2 = new String("abc");
        String str3 = str2.intern();
        System.out.println("str1==str2: " + (str1 == str2)); // false
        System.out.println("str2==str3: " + (str2 == str3)); // false
        System.out.println("str1==str3: " + (str1 == str3)); // true
}

运行结果:

str1==str2: false
str2==str3: false
str1==str3: true

分析,str2.intern()被调用时,str1 = “abc” 已经将“abc”放入了常量池,根据方法注释,str3返回的是拿到的是常量池中的str1,str2还是对象引用。所以有了上面的结果。

示例二:

public static void main(String[] args) {

        String str1 = new String("abc");
        String str2 = new String("abc");
        System.out.println(str1 == str2); //false
        System.out.println(str1.intern() == str2.intern()); //true
}

运行结果:

false
true

分析,str1==str2为false就不用说了;str1.intern() == str2.intern()为true,在英文注释里有说:

s.intern() == t.intern() is true if and only if s.equals(t) is true.

也是就是两个String对象,当且仅当它俩equals()比较值为true,那它俩intern()的“==”操作也为true。


示例三:

public static void main(String[] args) {

        String str1 = new String("abc");
        String str2 = str1.intern();
        String str3 = "abc";
        System.out.println(str1 == str3); //false
        System.out.println(str3 == str2); //true
}

运行结果:

false
true

分析,new Sting() 会在堆内创建一个str1的String对象,“abc”会添加到常量池,在调用intern()方法时,会去常量池中查找是否有相等的字符串字面量和对象引用,此时有“abc”就返回了“abc”,所以str3 == str2为true。str1 == str3为false就不用说了。

示例四:

类成员变量也会add到常量池。

public static void main(String[] args) {

        Teacher teacher = new Teacher();
        teacher.setName("King");
        String name = teacher.getName();
        String str = "King";
        System.out.println(name == str); // true
    }

    static class Teacher {
        private String name;
        private Integer age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }
    }

运行结果:

true

分析,类的成员变量在Class常量池中,英文文档上没有说明,但代码示例验证后,说明类成员变量也会放到常量池。

示例五:

public static void main(String[] args) {

        String s1 = new String("abc") + new String("abc");
        String s2 = s1.intern();
        String s3 = "abc" + "abc";

        System.out.println(s1 == s2); //true
        System.out.println(s2 == s3); //true
        System.out.println(s1 == s3); //true
}

运行结果:

true
true
true

分析,“new String(“abc”) + new String(“abc”)”首先会创建这两个对象以及相加后的对象,然后在常量池放入“abc”且对象指向该字面量。当s1调用intern()时因为没有“abcabc”的字面量,然后在常量池添加了s1的对象引用,返回给s2。所以,s1 == s2为true。““abc” + “abc””双引号相加,会判断这两个常量、相加后的常量在常量池上是否存在,

如果不存在
   则在常量池上创建相应的常量
  如果存在
   判断这个常量是存在的引用还是常量,
    如果是引用,返回引用地址指向的堆空间对象,
    如果是常量,则直接返回常量池常量

所以,““abc” + “abc””等同于“new String(“abc”) + new String(“abc”)”,s2 == s3与s1 == s3都为true。


花了不少时间分析、总结出来的,希望能帮助阅读者更快地理解它。
至此,本篇结束。

本文地址:https://blog.csdn.net/WLQ0621/article/details/107465898

相关标签: Java String