首页 > 编程笔记

Java String类用法详解

在 java 中,String 是我们实际开发中使用频率很高的类,Java 通过 String 类来创建和操作字符串数据。

本节就为大家详细讲解 String 类。

String实例化

String 类对象的实例化方式有两种,第 1 种是直接赋值的方式,第 2 种是通过构造函数创建实例化对象的方式。

String 类有一个带参数的构造函数:
public String(String original)
将 String 对象的值直接传入即可创建。

下面的实例程序演示了两种方式的具体操作。
public class StringTest {
   public static void main(String[] args) {
      //第一种方式直接赋值
      String str1 = "Hello";
      //第二种方式通过构造函数
      String str2 = new String("World");
      System.out.println(str1);
      System.out.println(str2);
   }
}
运行结果为:

Hello
World


两种实例化方式有什么不同呢?哪种方式更优呢?我们先来看下面的代码:
public class StringTest {
   public static void main(String[] args) {
      String str1 = "Hello";
      String str2 = "Hello";
      System.out.println(str1 == str2);
      String str3 = new String("World");
      String str4 = new String("World");
      System.out.println(str3 == str4);
   }
}
上述代码非常简单,用直接赋值的方式创建了 String 对象 str1 和 str2,并且值相等。又用构造函数的方式创建了 String 对象 str3 和 str4,同样值相等。然后用 == 分别判断 str1 和 str2 是否相等,以及 str3 和 str4 是否相等。

== 判断的并不是对象的值是否相等,而是判断对象所引用的内存地址是否相等。

运行结果为:

true
false

通过结果我们可以得出结论,str1 所引用的内存地址和 str2 所引用的内存地址相同,即 str1 和 str2 指向堆内存中的同一块位置。而 str3 和 str4 则指向堆内存中不同的位置,那么问题来了,在值相等的情况下,为什么会有截然不同的两种结果呢?

这是因为第一种直接赋值的方式如“String str1 = "Hello"”,会首先在栈内存中开辟一块空间来保存变量 str1,同时在堆内存中开辟一块合适的空间来存储“Hello”,然后将堆内存的地址赋给栈内存中的 str1,即 str1 中存储的是“Hello”的内存地址。Java 同时在堆内存中提供了一个字符串常量池,专门用来存储 String 类型的对象。

此外字符串常量池有一个特点,在实例化一个 String 对象时,首先会在字符串常量池中查找,如果该字符串已经在池中创建,则直接返回它的内存地址。如果字符串常量池中不存在该字符串,就先创建再返回,即字符串常量池中不会创建值相等的重复字符串对象,str1 和 str2 的创建如下图所示。


所以 str1 == str2 的返回值是 true,但是字符串常量池只适用于直接赋值的方式。如果是通过构造函数创建的对象则完全不同,这种方式创建的对象会在堆内存中开辟对应的空间来存储。即通过 new String("World") 和 new String("World") 创建了两个对象,虽然值相等,但是会开辟两块内存来存储,所以内存地址肯定是不同的,str3 和 str4 的创建如下图所示。


所以 str3 == str4 的返回值为 false,我们在了解了 String 类使用构造函数创建实例化对象的内存模型之后,当判断两个字符串对象是否相同时,就可以直接使用 == 进行判断了。因为 == 可以比较内存地址,两个字符串的值无论是否相等,其内存地址肯定不同。

那么我们要如何来判断两个字符串对象的值是否相等呢?

String 类对继承自 Object 类的 equals() 方法进行了重写,在判断两个字符串对象是否相同时,equals() 会直接将字符串转为 byte 类型的数组,然后依次判断数组中的每一个值是否相等。如果全部相等,则认为两个字符串相等,返回 true,否则返回 false,表示两个字符串不相同。我们在判断两个字符串对象的值是否相等时,直接调用 String 的 equals() 方法即可。

实际上 String 类在存储字符串时,会将字符串的值保存在 byte 类型的数组中,我们知道数组一旦创建,其长度就是不可改变的。既然长度不可改变,也就意味着 byte 类型所存储的字符串值不可修改。一旦修改,就会重新创建一个 String 对象,用新对象的 byte 数组来存储修改之后的字符串。即如果我们修改了 String 对象的值,它就已经不是之前的对象了,而是一个新的对象,实例代码如下:
public class StringTest {
   public static void main(String[] args) {
      String str1 = new String("Hello");
      String str2 = str1;
      System.out.println(str2 == str1);
      str1 += " World";
      System.out.println(str2 == str1);
   }
}
运行结果为:

true
false

String常用方法

String 类提供了大量的方法,在实际开发中使用这些方法可以很方便地完成对字符串的操作,常用方法如下表所示。

方 法 描 述
public String() 创建一个值为空的对象
public String(String original) 创建一个值为 original 的对象
public String(char value[]) 将一个 char 型数组转为字符串对象
public String(char valued, int offset, int count) 将一个指定范围的 chars 数组转为字符串对象
public String(byte[] bytes) 将一个 byte 型数组转为字符串对象
public String(byte bytes[], int offset, int length) 将一个指定范围的 byte 型数组转为字符串对象
public int length() 返回字符串的长度
public boolean isEmpty() 判断字符串是否为空
public char charAt(int index) 返回字符串中指定位置的字符
public byte[] getBytes() 将字符串转为 byte 型数组
public boolean equals(Object anObject) 判断两个字符串是否相等
public boolean equalslgnoreCase(String anotherString) 判断两个字符串是否相等并且忽賂大小写
public int compareTo(String anotherString) 对两个字符串进行排序
public boolean startsWith(String prefix) 判断是否以指定的值开头
public boolean endsWith(String suffix) 判断是否以指定的值结尾
public int hashCode() 获取字符串的散列值
public int indexOf(String str) 从头开始查找指定字符的位置
public int indexOf(String str, int fromlndex) 从指定的位置开始查找指定字符的位置
public String substring(int beginlndex) 截取字符串从指定位置开始到结尾
public String substring(int beginlndex, int endindex) 裁取字符串从指定位置开始到指定位置结束
public String concat(String str) 追加字符串
public String replaceAll(String regex, String replacement) 替换字符串
public String[] split(String regex) 用指定字符串对目标字符串进行分割,返回数组
public String toLowerCase() 将字符串转为小写
public String toUpperCase() 将字符串转为大写
public char[] toCharArray() 将字符串转为 char 型数组

例如:
public class StringTest {
   public static void main(String[] args) {
      char[] array = {'J','a','v','a',',','H','e','l','l','o',',','W','o','r','l','d'};
      String str = new String(array);
      System.out.println(str);
      System.out.println("str长度:"+str.length());
      System.out.println("str是否为空:"+str.isEmpty());
      System.out.println("下标为2的字符是:"+str.charAt(2));
      System.out.println("H的下标是:"+str.indexOf('H'));
      String str2 = "Hello";
      System.out.println("str和str2是否相等:"+str.equals(str2));
      String str3 = "HELLO";
      System.out.println("str2和str3忽略大小写是否相等:"+str2.equalsIgnoreCase(str3));
      System.out.println("str是否以Java开头:"+str.startsWith("Java"));
      System.out.println("str是否以Java结尾:"+str.endsWith("Java"));
      System.out.println("从2开始截取str:"+str.substring(2));
      System.out.println("从2到6截取str:"+str.substring(2, 6));
      System.out.println("将str中的World替换为Java:"+str.replaceAll("World", "Java"));
      System.out.println("用逗号分割str:"+Arrays.toString(str.split(",")));
      System.out.println("将str转为char类型数组:"+Arrays.toString(str.toCharArray()));
      System.out.println("str3转为小写:"+str3.toLowerCase());
      System.out.println("str2转为大写:"+str2.toUpperCase());
   }
}
运行结果为:

Java,Hello,World 
str长度:16 
str是否为空:false 
下标为2的字符是:v 
H的下标是:5 
str和str2是否相等:false 
str2和str3忽略大小写是否相等:true 
str是否以Java开头:true 
str是否以Java结尾:false 
从2开始截取str:va,Hello,World 
从2到6截取str:va,H 
将str中的World替换为Java:Java,Hello,Java 
用逗号分割str:[Java, Hello, World] 
将str转为char类型数组:[J, a, v, a, , H, e, l, l, o, , W, o, r, l, d] 
str3转为小写:hello 
str2转为大写:HELLO

推荐阅读