字符串

String 被声明为 final,因此它不可被继承,它们的值在创建之后不能修改。

1、String 源码片段

java.lang.String

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

/** String的属性值 */  
private final char value[];

/**数组被使用的开始位置**/
private final int offset;

/**String中元素的个数**/
private final int count;

/**String类型的hash值**/
private int hash; // Default to 0

......

从源码看出:

  • String 底层使用一个字符数组来维护(Java8)。Java9 后使用 byte 数据,可参考 Java9后String的空间优化 。
  • value 数组被 final 修饰,意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,从而保证 String 不可变。

2、创建字符串对象两种方式

  • 直接赋值创建的对象是存放在方法区的常量池中。
String str="hello";
  • 通过构造方法创建的对象存放在堆内存中。
String str=new String("hello");

创建字符串的练习:

1、 String str = "123";

如上:jvm在编译阶段会判断常量池中是否有 “123” 字面量。若有,str 直接指向这个字面量的引用,如果没有会在常量池里创建这个字面量。

2、 String str = new String("123");

如上:jvm 编译时期判断常量池中 “123” 是否存在,从而判断是否创建字面量,然后运行时期通过 new 关键字在 java heap 中创建 String 对象。

    String a = "a";
    String b = "b";
    String str = "ab";
3、 System.out.println(str == "a" + "b"); // true
4、 System.out.println(ab == a + b); // false

如3:字面量"+"拼接是在编译期间进行的。jvm编译阶段过编译器会把字符串常量直接合并成 “ab”,所以创建对象时可能会在常量池中创建1个对象。

字面量"+“拼接是在编译期间进行的。jvm编译阶段过编译器会把字符串常量直接合并成"ab”,所以创建对象时可能会在常量池中创建1个对象。
字符串引用的"+"拼接运算实在运行时进行的,新创建的字符串存放在堆中。

3、字符串常量池

字符串常量池(String Pool)保存所有字符串字面量(literal strings),这些字面量在编译时期就确定。

可以使用 String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中。

String s1 = new String("intern test");
String s2 = new String("intern test");
System.out.println(s1 == s2); // false
String s3 = s1.intern();
String s4 = s1.intern();
System.out.println(s3 == s4); // true

如上:当一个字符串调用 intern() 时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法确定),那么就会返回 String Pool 中字符串的引用;否则,会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。

4、String, StringBuffer & StringBuilder

基本区别

  • String 不可变,因此是线程安全的
  • StringBuilder 可变,不是线程安全的
  • StringBuffer 可变,是线程安全的,内部使用 synchronized 进行同步

使用场景

  • 在字符串不经常发生变化的业务场景优先使用 String。(如常量的声明,少量的字符串操作)

  • 在单线程情况下,若有大量的字符串操作情况,应使用 StringBuilder 来操作字符串。使用 String"+" 来拼接会产生大量无用的中间对象,耗费空间且执行效率低下。(如封装 JSON 数据)

  • 在多线程情况下,若有大量的字符串操作情况,应使用 StringBuffer。(如 HTTP 参数解析和封装)

你可能感兴趣的:(java)