Java字符串表示方式有三种:
-
字符串常量,以双引号括起来的内容
1
String literialStr = “字符串常量”;
-
字符数组,以单引号括起来的内容表示一个字符,多个连起来表示字符串,String内部就是用字符数组来表示的
1
char[] chars = {'字', '符', '串', '常', '量'};
-
String实例
1
String strs = new String("字符串常量");
字符串特性:
-
比较,使用==比较的是两个字符串是否引用同一个对象;使用equals比较两个字符串内容是否相等
-
StringBuilder(多线程不安全)和StringBuffer(多线程安全)的toString方法返回的是new String("…")
-
字符串常量池,javap -verbose ClassName,反编译类后可以看到一个java文件被编译成class文件后的结构和内容。其中有一项结构是Constant pool(常量池),它里面会保存此class文件用到的所有常量包括类名、方法名、字符串常量。当class文件被载入jvm运行时,字符串常量池也会相应的载入内存成为运行时常量池。个人理解类似程序和进程的概念,一种是静态的描述,一种是载入内存后动态的表示。
-
intern方法,查看JDK文档,关注重点:
- 调用intern方法时,会从字符串常量池去找,如果找到(通过equals方法判断),直接返回字符串常量池的引用
- 没有找到,则会将此String对象加入字符串常量池(字符串常量池此时将建立一个执向堆内存String对象的引用),然后还是返回字符串常量池的引用(注意:此时字符串常量池的引用指向堆内存的String对象)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24/**
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
* class {@code String}.
* <p>
* 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.
* <p>
* 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}.
* <p>
* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
* <cite>The Java™ Language Specification</cite>.
*
* @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();
下面,基于intern的处理逻辑,看看几个例子
参考: https://developer.aliyun.com/article/48686
第一个:
1 | //首先,将"string_test_1"存入字符串常量池,然后在堆上创建一个String对象,并返回堆上String对象的引用 |
第二个:
1 | //直接在堆上创建一个String对象,并返回堆上String对象的引用 |
第三个:
1 | //首先,将"same1"存入字符串常量池,并返回字符串常量池里String对象的引用 |
第四个:
1 | //首先,将"same2"存入字符串常量池,然后在堆上创建一个String对象,并返回堆上String对象的引用 |
第五个:
1 | //将"first"存入字符串常量池,并返回字符串常量池里String对象的引用 |
第六个:
1 | final String s1 = "first"; |