本文主要说明String中的一些特性以及常用方法,如果要探究String字符串池以及运行原理或者机制等深入内容,请看本文最底部的参考文献。
目录:
2.3:StringBuilder与StringBuffer
1:String的数据类型
这是很多新人都会犯一个错误,在JAVA八大基本数据类型中,不包括String,在 Java 中,String
是一种特殊的引用数据类型。尽管它在使用时类似于基本数据类型,但实际上它是一个类,属于引用数据类型的范畴。
在 Java 中,基本数据类型有固定的大小和默认值,而 String
类型是不定长度的,可以存储任意长度的字符串。由于 String
类具有对象的特性,它可以调用方法来进行字符串操作,而基本数据类型需要转化为对应的引用数据类型才可以进行对象操作。
虽然
String
是引用数据类型,但 Java 在字符串处理上进行了优化,允许字符串直接使用类似基本数据类型的赋值方式,这被称为字符串常量池。在许多情况下,字符串常量池的使用方式让String
类型的使用看起来更像是基本数据类型,但它仍然是引用数据类型。
2:String的一些重要特点
2.1:不可变性(Immutability)及其意义
首先我们来看一下String的源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
}
String是final类,在Java中,String
类是一个非常特殊的类,它具有不可变性,也就是一旦创建了一个字符串对象,就不能修改其内容。
(1)创建后不可改变:
一旦创建了字符串对象,它的内容就无法被修改。例如,当对一个已经存在的字符串进行拼接、插入或删除操作时,会创建一个新的 String
对象,然后将新的值赋给原来的字符串引用。原来的字符串对象本身不会被修改,而是指向了一个全新的字符串对象。对于字符串拼接的情况,Java 编译器会自动优化一些简单的拼接操作,将其转换为使用 StringBuilder
或 StringBuffer
来处理,以提高性能。但是不论是否使用这些类,基本思想仍然是创建一个新的字符串对象。
(2)字符串池:
由于字符串是不可变的,Java 可以有效地将字符串放入字符串池中。字符串池是一个特殊的内存区域,用于存储常用的字符串对象。当你创建一个字符串对象时,Java 首先会检查字符串池中是否已经存在相同内容的字符串,如果存在,就会返回池中的引用,而不会创建新的对象。这可以节省内存,并提高性能。
需要注意的是:字符串池中的字符串不会被垃圾回收,因此需要注意避免过多的字符串池中的引用,以防止内存泄漏,而且由于字符串不可变性,当一个字符串不再被引用时,它会成为垃圾收集的候选对象,从而释放内存。
内存泄漏:是指程序中的一些对象在不再使用时仍然被占用着内存,从而导致系统的可用内存逐渐减少,最终可能导致系统性能下降甚至崩溃。
(关于字符串池的深入内容可以看一下下面的参考文献)
(3) 安全性(线程安全):
基于字符串不可变性提供了一定的安全性。由于字符串的内容不会被修改,因此多个线程可以同时访问同一个字符串对象,而不会出现竞争条件。这在多线程编程中是很有用的,因为不需要额外的同步操作来保证数据一致性。
2.2:字符串的比较
在JAVA中,对String类进行比较常用三种方法,equals(),==,以及compareTo()。
(1)equals():
equals()
方法用于比较两个字符串的内容是否相等。它是在java.lang.String
类中定义的,重写了Object
类中的equals()
方法。这个方法会比较字符串的每个字符是否一致,如果每个字符都一致,就返回 true
,否则返回 false
。适用范围:主要用于比较对象的内容是否相等,如字符串、自定义类等。
String str1="abc";
String str2="cba";
String str3="abc";
System.out.println(str1.equals(str2)); //输出false
System.out.println(str1.equals(str3)); //输出true
(2)==:
使用 ==
运算符可以比较两个字符串的引用,即判断两个引用是否指向同一个对象。适用范围:用于判断两个对象是否是同一个实例,不会对对象的内容进行比较。对于基本数据类型,它比较的是值是否相等。
String str1="abc";
String str2="abc";
String str3= new String("abc");
System.out.println(str1==str2); //返回true
System.out.println(str1==str3); //返回false
str1
和 str2
都使用字符串文字"abc" 来初始化,这种情况下,Java 会在编译时优化,使得它们指向同一个字符串常量池中的对象(忘了的看一下上面的字符串池)。因此,str1 == str2
会返回 true
,因为它们引用了相同的字符串对象。
str3
使用 new String("abc")
显式地创建了一个新的字符串对象。不同于字符串文字的优化,这会在堆内存中创建一个新的字符串对象。
(3)compareTo():
compareTo()
方法用于比较两个字符串的大小关系。它是在java.lang.String
类中定义的,实现了Comparable
接口。该方法返回一个整数值,表示字符串之间的大小关系。如果字符串相等,返回值为 0。如果调用者字符串在字典顺序中位于参数字符串之前,则返回负数。如果调用者字符串在字典顺序中位于参数字符串之后,则返回正数。适用范围:主要用于对对象进行排序或确定它们的相对顺序,如数字、日期等。
String str1="abc";
String str2="abc";
String str3= new String("cba");
System.out.println(str1.compareTo(str2));//字符串相等返回值为0
System.out.println(str1.compareTo(str3));//调用者str1在str3之前 返回负数
System.out.println(str3.compareTo(str1));//反之 正数
(4)总结:
使用
equals()
进行内容比较,适合判断对象的属性值是否相等。使用
==
运算符进行引用比较,适合判断两个引用是否指向同一个实例。使用
compareTo()
方法进行大小比较,适合对可比较对象进行排序或确定相对顺序。
2.3:StringBuilder与StringBuffer
StringBuilder
和 StringBuffer
都是用来处理可变字符串的类,它们在字符串操作中比直接使用 String
类更高效。两者的主要区别在于线程安全性和性能。刚才我们提到String不可变性时,对于字符串的修改优化,使用StringBuilder
或 StringBuffer。
String
适用于不需要频繁修改的情况,例如存储常量或不变的字符串。
StringBuilder
是非线程安全的,适用于单线程环境下的频繁字符串拼接操作。
StringBuffer
是线程安全的,适用于多线程环境下的字符串拼接操作。
StringBuilder
或 StringBuffer在进行修改的时候不创建新的字符串对象,而是对原有的字符串对象进行操作。(关于他俩的细节在下个篇章之中再聊,这里简单介绍一下)
3:常用的String操作
1.字符串的拼接:使用 +
运算符或 concat()
方法可以将多个字符串拼接成一个新的字符串。
2.获取字符串长度:使用 length()
方法可以获取字符串的长度。
.length()
: 这是一个方法,用于获取字符串、数组和集合等对象的长度或大小。
length
: 这是一个属性(或字段),主要用于获取数组的长度。它是一个在创建数组时就确定的常量,表示数组可以容纳的元素个数。
3.字符串提取:使用 substring(int startIndex)
或 substring(int startIndex, int endIndex)
方法可以从原字符串中提取子字符串。int startIndex:开始下标 int endIndex 结束下标(从0开始 空格也算)
String original = "Hello, world!";
String subString = original.substring(7); // "world!"
String subString2 = original.substring(0, 5); // "Hello"
4.字符串查找: 使用 indexOf(String str)
或 lastIndexOf(String str)
方法可以查找某个子字符串在原字符串中的位置。
indexOf(String str):第一次出现的位置 从0开始 空格也算
lastIndexOf(String str):最后一次出现的位置
String sentence = "Java is a programming language.";
int indexOfIs = sentence.indexOf("is"); // 5
int lastIndexOfA = sentence.lastIndexOf("a"); // 27
5.字符串替换:使用 replace(old, new)
方法可以将指定的子字符串替换为新的字符串。
他会替换所有的字符串!!!!
String sentence = "Java is a programming language.";
String str2 = sentence.replace("a", "6");
String str3 = sentence.replace("is", "are");
System.out.println(str2); //J6v6 is 6 progr6mming l6ngu6ge.
System.out.println(str3); //Java are a programming language.
6.字符串分割:使用 split(String regex)
方法可以将字符串分割成字符串数组。
String numbers = "1,2,3,4,5";
String[] numberArray = numbers.split(",");
for(String a:numberArray){
System.out.println(a);// 1 2 3 4 5
}
7.字符串转换大小写: 使用 toUpperCase()
和 toLowerCase()
方法可以将字符串转换为大写或小写形式。
8.去除首尾空格: 使用 trim()
方法可以去除字符串首尾的空格。
9.判断前缀和后缀: 使用 startsWith(String prefix)
和 endsWith(String suffix)
方法可以判断字符串是否以指定的前缀或后缀开始或结束。
10.字符串转换: 使用 valueOf()
方法可以将其他数据类型转换为字符串
valueOf()
用于将基本数据类型和引用数据类型转换为字符串。
toString()
用于将对象转换为字符串,每个对象类都可以重写此方法以自定义字符串表示。
11.字符串反转: 使用 StringBuilder
或 StringBuffer
类的 reverse()
方法可以反转字符串。