字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。 String
类是不可改变的,所以一旦创建了 String 对象,那它的值就无法改变了。 如果需要对字符串做很多修改,那么应该选择使用
StringBuffer & StringBuilder 类
为什么String类是不可改变的?
String s = "AAAA";
System.out.println("s = " + s);
s = "BBBB";
System.out.println("s = " + s);
输出结果:
AAAA
BBBB
从结果上看是改变了,但为什么说String对象是不可变的呢?
原因在于实例中的 s 只是一个 String 对象的引用,并不是对象本身,当执行 s = “BBBB”; 创建了一个新的对象 “BBBB”,而原来的 “AAAA” 还存在于内存中。
如图:
或者根据 jdk 的源码来分析。
字符串实际上就是一个 char 数组,并且内部就是封装了一个 char 数组。
并且这里 char 数组是被 final 修饰的:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
并且 String 中的所有的方法,都是对于 char 数组的改变,只要是对它的改变,方法内部都是返回一个新的 String 实例。
Java:String、StringBuffer 和 StringBuilder 的区别
String:字符串常量,字符串长度不可变。Java中String 是immutable(不可变)的。用于存放字符的数组被声明为final的,因此只能赋值一次,不可再更改。
StringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于效率考虑最好使用 StringBuffer,如果想转成 String 类型,可以调用 StringBuffer 的 toString() 方法。Java.lang.StringBuffer 线程安全的可变字符序列。在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。
StringBuilder:字符串变量(非线程安全)。在内部 StringBuilder 对象被当作是一个包含字符序列的变长数组。
基本原则:
- 如果要操作少量的数据用 String ;
- 单线程操作大量数据用StringBuilder ;
- 多线程操作大量数据,用StringBuffer。
String类支持的方法:
-
获取字符串长度 用于获取有关对象的信息的方法称为访问器方法。
- String 类的一个访问器方法是 length() 方法
- 1、length() 方法是针对字符串来说的,要求一个字符串的长度就要用到它的length()方法;
- 2、length 属性是针对 Java 中的数组来说的,要求数组的长度可以用其 length 属性;
- 3、Java 中的 size() 方法是针对泛型集合说的, 如果想看这个泛型有多少个元素, 就调用此方法来查看!
- String 类的一个访问器方法是 length() 方法
-
连接字符串
-
concat() 方法
-
'+'操作符
-
String a = "a"; String b = "b"; String c = a + b;
相当于:
String c = new StringBuffer().append(a).append(b).toString();
对于字符串的加运算,当编译成 class 文件时,会自动编译为 StringBuffer 来进行字符串的连接操作。
同时对于字符串常量池:
当一个字符串是一个字面量时,它会被放到一个常量池中,等待复用。
String a = "saff"; String b = "saff"; String c = new String("saff"); System.out.println(a.equal(b)); // true System.out.println(a.equal(c)); // true
这个就是字符串的常量池。
-
-
-
创建格式化字符串
- String 类的静态方法 format() 能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出。
-
返回指定索引处的 char 值
- charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。
-
字符串与对象进行比较、按字典顺序比较两个字符串
-
int compareTo(Object o)
-
compareTo(String anotherString)
-
关于这个方法,不管参数是对象还是字符串,最终要比较的都是两个字符串的不同,以下称调用方法那边的为原字符串,方法参数里的为参数字符串。
这个方法分为两种比较方式:
1、不同的字符在较短字符串长度之内时
2、不同的字符在较短字符串长度之外时
-
看下 compareTo 的源码:
/* *如果参数字符串等于此字符串,则返回值 0; *如果此字符串按字典顺序小于字符串参数,则*返回一个小于 0 的值; *如果此字符串按字典顺序大于字符串参数,则返回一个大于 0 的值。 */ public int compareTo(String anotherString) { int len1 = value.length; int len2 = anotherString.value.length; //取数组长度里面最小的 int lim = Math.min(len1, len2); // 获得两个数组,这两个数组就是string的属性 char v1[] = value; char v2[] = anotherString.value; int k = 0; while (k < lim) { //获取第K的字符,进行比较 char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { //Java使用的是Unicode编码,因此返回这两个字符的Unicode差值。 return c1 - c2; } k++; } //如果前lim个字符都相同,那么就返回长度差。 return len1 - len2; }
- 1、取得string的value数组
- 2、取得value数组里面的元素
- 3、按照unicode值进行比较
- 4、返回比较的值
String a = "a"; String b = "b"; System.out.println(a.compareTo(b));
输出值 -1。
String a = "b"; String b = "a"; System.out.println(a.compareTo(b));
输出值 1。
String a = "a"; String b = "a"; System.out.println(a.compareTo(b));
输出 0。
两个字符串首字母不同,则该方法返回首字母的 asc 码的差值。
String a = "abc"; String b = "bcdfg"; System.out.println(a.compareTo(b));
输出 -1。
参与比较的两个字符串如果首字符相同,则比较下一个字符,直到有不同的为止,返回该不同的字符的 ascii 码差值。
String a = "abc"; String b = "abedfg"; System.out.println(a.compareTo(b));
输出 -2。
两个字符串不一样长,可以参与比较的字符又完全一样,则返回两个字符串的长度差值。
String a = "abc"; String b = "abcdefg"; System.out.println(a.compareTo(b));
输出 -4。
string a = "abcde"; String b = "abcd"; System.out.println(a.compareTo(b));
输出 1。
目前 compareTo 项目中的用途是比较版本号的高低。
String a = "1.0.0"; String b = "1.0.1"; System.out.println(a.compareTo(b));
输出 -1。
-
-
-
-
按字典顺序比较两个字符串,不考虑大小写
-
compareToIgnoreCase()
-
关于这个方法,不管参数是对象还是字符串,最终要比较的都是两个字符串的不同,以下称调用方法那边的为原字符串,方法参数里的为参数字符串。
这个方法分为两种比较方式:
1、不同的字符在较短字符串长度之内时
返回值=原字符串与参数字符串中第一个不同字符相差的ASCII码值,为原减参。
例子如下:
String str1="javDscrspt"; String str2="jAvascript"; str1.compareToIgnoreCase(str2);
此时返回值为3,是d的ASCII码(100)减去了a的ASCII码值(97)得到或者D与A相差得到的。
注意:只比较第一个不同(这个方法里不考虑字母大小写)的字符,后面的s和i也不一样但不会进行比较了,无关字母大小写所以只比较相同格式下相差的ASCII码值。
2、不同的字符在较短字符串长度之外时
返回=原字符串与参数字符串相差的字符个数,原字符串长度大时为正,反之为负。
例子如下:
String str1="javAScript"; String str2="JaVa"; str1.compareToIgnoreCase(str2);
此时返回值为6,是str1相比str2多出来的字符个数。
注意:此时只比较位数,而无关ASCII码值,并非是S(s)的ASCII码值减去0的ASCII码值,在参数字符串前面字符和原字符串一样时,返回值就是两者相差的字符个数,即使改变后面的字符也不会影响到返回的值,比如String str1=“jAva233666”,此时结果仍是6。
-
-
-
当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回真
- boolean contentEquals(StringBuffer sb)
-
返回指定数组中表示该字符序列的 String
- static String copyValueOf(char[] data)
- static String copyValueOf(char[] data, int offset, int count)
-
测试此字符串是否以指定的后缀结束
- boolean endsWith(String suffix)
-
将字符串与指定的对象比较,不考虑大小写
- boolean equalsIgnoreCase(String anotherString)
-
使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中
-
byte[] getBytes()
-
可用如下方法查看字符串用 getBytes() 方法处理后返回的 byte[] 数组中的内容:
class Main { public static void main(String[] args) { String str = "make a fortune"; byte[] byt = str.getBytes(); for (byte b : byt) { System.out.println(b); } } }
以上程序运行结果为:
109 97 107 101 32 97 32 102 111 114 116 117 110 101
可见 byte[] 数组中存放的是字符串响应位置对应的字母的哈希值,如字符串中的字母 a 对应 byte[] 数组中的 97 。
另外:返回的 byte[] 数组的长度,与原字符串的长度相等
-
-
-
使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中
- byte[] getBytes(String charsetName)
-
将字符从此字符串复制到目标字符数组
- void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
-
返回此字符串的哈希码
- int hashCode()
-
返回指定字符在此字符串中第一次出现处的索引
- int indexOf()
-
返回字符串对象的规范化表示形式
-
String intern()
-
尽管在输出中调用intern方法并没有什么效果,但是实际上后台这个方法会做一系列的动作和操作。在调用”ab”.intern()方法的时候会返回”ab”,但是这个方法会首先检查字符串池中是否有”ab”这个字符串,如果存在则返回这个字符串的引用,否则就将这个字符串添加到字符串池中,然会返回这个字符串的引用。
可以看下面一个范例:
String str1 = "a"; String str2 = "b"; String str3 = "ab"; String str4 = str1 + str2; String str5 = new String("ab"); System.out.println(str5.equals(str3)); System.out.println(str5 == str3); System.out.println(str5.intern() == str3); System.out.println(str5.intern() == str4);
得到的结果:
true false true false
为什么会得到这样的一个结果呢?我们一步一步的分析。
- 第一、str5.equals(str3)这个结果为true,不用太多的解释,因为字符串的值的内容相同。
- 第二、str5 == str3对比的是引用的地址是否相同,由于str5采用new String方式定义的,所以地址引用一定不相等。所以结果为false。
- 第三、当str5调用intern的时候,会检查字符串池中是否含有该字符串。由于之前定义的str3已经进入字符串池中,所以会得到相同的引用。
- 第四,当str4 = str1 + str2后,str4的值也为”ab”,但是为什么这个结果会是false呢?先看下面代码:
String a = new String("ab"); String b = new String("ab"); String c = "ab"; String d = "a" + "b"; String e = "b"; String f = "a" + e; System.out.println(b.intern() == a); System.out.println(b.intern() == c); System.out.println(b.intern() == d); System.out.println(b.intern() == f); System.out.println(b.intern() == a.intern());
运行结果:
false true true false true
由运行结果可以看出来,b.intern() == a和b.intern() == c可知,采用new 创建的字符串对象不进入字符串池,并且通过b.intern() == d和b.intern() == f可知,字符串相加的时候,都是静态字符串的结果会添加到字符串池,如果其中含有变量(如f中的e)则不会进入字符串池中。但是字符串一旦进入字符串池中,就会先查找池中有无此对象。如果有此对象,则让对象引用指向此对象。如果无此对象,则先创建此对象,再让对象引用指向此对象。
当研究到这个地方的时候,突然想起来经常遇到的一个比较经典的Java问题,就是对比equal和的区别,当时记得老师只是说“”判断的是“地址”,但是并没说清楚什么时候会有地址相等的情况。现在看来,在定义变量的时候赋值,如果赋值的是静态的字符串,就会执行进入字符串池的操作,如果池中含有该字符串,则返回引用。
执行下面的代码:
String a = "abc"; String b = "abc"; String c = "a" + "b" + "c"; String d = "a" + "bc"; String e = "ab" + "c"; System.out.println(a == b); System.out.println(a == c); System.out.println(a == d); System.out.println(a == e); System.out.println(c == d); System.out.println(c == e);
运行的结果:
true true true true true true
-
-
-
返回指定字符在此字符串中最后一次出现处的索引
- lastIndexOf()
-
检测字符串是否匹配给定的正则表达式
- matches()
-
测试两个字符串区域是否相等
- boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
-
替换为新字符串
- replace()
-
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串
- replaceAll()
-
使用给定的参数 replacement 替换字符串第一个匹配给定的正则表达式的子字符串
- replaceFirst()
-
根据给定正则表达式的匹配拆分此字符串
-
split()
-
. 必须得加转义字符**\**,以下是拆分 IP 地址的实例:
public class Demo { public static void main(String args[]) { String str = "192.168.1.1"; // . 必须得加 转义字符\\ for(String s : str.split("\\.")){ System.out.println(s); } } }
-
-
-
检测字符串是否以指定的前缀开始
- startsWith()
-
返回一个新的字符序列,它是此序列的一个子序列
- subSequence() (返回的是String)
- substring() (返回的是实现了CharSequence接口的类,可以直接下转为String对象)
-
将字符串转换为字符数组
- toCharArray()
-
将字符串转换为小写
- toLowerCase()
-
返回此对象本身
- toString()
-
将字符串小写字符转换为大写
- toUpperCase()
-
用于删除字符串的头尾空白符
- trim()
-
返回给定data type类型x参数的字符串表示形式
- valueOf()
System.out.println(s);
}
}
}
```
-
检测字符串是否以指定的前缀开始
- startsWith()
-
返回一个新的字符序列,它是此序列的一个子序列
- subSequence() (返回的是String)
- substring() (返回的是实现了CharSequence接口的类,可以直接下转为String对象)
-
将字符串转换为字符数组
- toCharArray()
-
将字符串转换为小写
- toLowerCase()
-
返回此对象本身
- toString()
-
将字符串小写字符转换为大写
- toUpperCase()
-
用于删除字符串的头尾空白符
- trim()
-
返回给定data type类型x参数的字符串表示形式
- valueOf()