Java String

小小String,内有大文章。

String是Java中最常见的。正是因为它常见,所以大家经常忽略。但是在各种“高级别讨论”中又经常出现,因此自己尝试着总结一下。

  1. String的定义
  2. String的创建
  3. String的内存模型
  4. immutable
  5. String,StringBuilder,StringBuffer
  6. == vs equals
  7. intern()
  8. 一些测试题目

 

1 String的定义

学习任何东西最好从第一手资料开始。下面的文字摘自JDK中java.lang.String的头部。

/**
 * The {@code String} class represents character strings. All
 * string literals in Java programs, such as {@code "abc"}, are
 * implemented as instances of this class.
 * <p>
 * Strings are constant; their values cannot be changed after they
 * are created. String buffers support mutable strings.
 * Because String objects are immutable they can be shared. 

从这里看出字符串就是“一串字符”(废话!!)。所有的字面量都是字符串。

字符串是常量,一旦创建不可改变。这里有个专门术语叫做“immutable”。因为比较重要,后面又单独的一节来讲immutable。

这个定义和C++里面的定义完全不同。C++里面的字符串更像是StringBuilder。

且C/C++的字符串以'\0'结尾。Java的字符串不包括'\0',因为String里面有字符的个数。

下面是JDK自带的源代码定义

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {  
    private final char value[];
    private int hash; // Default to 0  
    private static final long serialVersionUID = -6849794470754667710L;
  
    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];

   //无参构造函数
    public String() {
        this.value = new char[0];
    }

   //最常用的构造函数,注意这里是浅拷贝。因为是immutable,无需实现深拷贝。
    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

   //入参为char数组的构造参数
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

   
    public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }
........  
   
}

  

 

 

2 String的创建

 (1) String str = "hello"; //在running constant pool创建"hello"
(2) char data[] = {'h', 'e', 'l','l','o'};//在栈上创建data String str = new String(data);//先去running consant pool里面查找有没有"hello",没有的话创建一个;且在堆上创建String对象,存放"hello"
(3) String str = new String("hello");//先去running consant pool里面查找有没有"hello",没有的话创建一个;且在堆上创建String对象,存放"hello"
(4)String str = "Hel" +"lo";//编译优化,在编译的时候就能确定str为"hello",优化为一个变量String str = "Hello"
(5)String str = "hel" + new String("lo"); //被编译器转化为str = (new StringBuilder()).append("hel").append("lo").toString();
1 load StringBuilder类

2 生成临时变量StringBuilder,保存"hel"字符串

3 执行String(String)的构造函数,得到字符串"lo"

4 执行StringBuilder.append() 把"lo” append到“hel”上得到字符串“hello”

5 执行StringBuilder.toString() 返回"hello”给变量S3.
View Code
(6)String stemp = "lo";
String str = "hel" + stemp;//同5,stemp是变量,编译时候不能确定,所以只能运行时候确定
(7)final String stemp = new String("lo");//new string运行时候才能确定,所以stemp无法编译优化
String str = "hel" + stemp;//同5
(8)final String stemp = "lo";//final常量,编译的时候能够确定
String str = "hel" + stemp;//同4,编译优化
(9)final String stemp = getFinalString();//虽然stemp是常量,但是函数调用只有在运行时才能确定
String str = "hel" + stemp;//同5,运行时确定
(10)你可以列出属于自己的方法

可以看到String的创建方法比较多,且背后的执行也不同。这个是“高级谈话”的开始。所以这里一定要弄清楚,每个创建方式的异同。

JAVA里面没有运算符重载,“hel” + new String("lo") 会被替代为StringBuilder执行程序。

3 String的内存模型

根据刚才String的创建过程,我们看到String主要是涉及到了running constant pool和heap。

4 immutable

5 String,StringBuilder,StringBuffer

String是不可变的;StringBuilder和StringBuffer的内容是可变的。

StringBuffer是线程安全的,从JDK1.0就引入了;

StringBuilder是线程不安全的,从JDK1.5引入。

String 是不可变的,如

String str = "hello";
String str = "world";//看上去是str指向的内容变了,其实是str指向"world"了,str不再直线“hello”。

6 == vs equals

==永远比较的地址

equals是祖宗Object的虚方法,String重载了此方法,用来比较内容是否相同

7 intern()

关于intern(),美团有这个牛的文章,自己实在不敢下笔了,直接转发过来。

http://tech.meituan.com/in_depth_understanding_string_intern.html

8 一些测试题目

8.1 写一个immutable类

8.2 下面代码的输出是什么

public class JavaTest {
        public static void main(String args[]) {
            String s1 = "123";
            String s2 = "123";
            String s3 = new String("123");
            System.out.println((s1 == s2) + " " + (s2 == s3));
            System.out.println((s1.equals(s2)) + " " + (s2.equals(s3)));
        }
}

 

posted on 2016-11-21 15:49  忍hone  阅读(247)  评论(0编辑  收藏  举报

导航