字符串的常用可想而知。
在Java里,字符串是一系列Unicode字符,用双引号表示。
例如:
String e = "";//空串,没有字符
String greeting = "Hello";//有5个字符
String类是Java自带的表示字符串的类。
1 子串
很显然,一个字符串可以划分为很多子串,甚至从数学的角度来说,它本身也是自己的子串嘛。
可以用字符串的一个subString()方法来获得子串。
//这里就取出了greeting字符串中的第0、1、2位置的字符,组成新的字符串
//字符串变量s就指向这个新的字符串"Hel",显然,这个字符串的长度是3 - 0 = 3
String s = greeting.subString(0, 3);
2 拼接字符串
用运算符+可以拼接两个字符串,形成新的字符串
String i = "I";//注意,只是一个字符串,不是字符,字符是用单引号
String love = "love";
String you = "you";
String state = i + " " + love + " " + you + "!";// state = "I love you!"这里空格也是一个字符的
注意:如果+号两边有一个是字符串,那么Java会自动调用不是字符串的那个类的toString()方法,来使这个位置变成一个字符串来进行拼接
int price = 13;
String apple = "Apple:"
String message = apple + price;//message = "Apple:13",这里Java自动把数字13变成字符串"13"
3 字符串是不可变的
一个字符串实例,一旦创建完成,就是不可更改的。
String greeting = "Hello";
greeting = greeting.subString(0, 3) + "p!";
//表面上看,greeting变量是改变了,实际上是重新造了个新的字符串,greeting变量指向新的字符串而已
//如果你看String类的源码,可以知道,String类内部用数组实现保存字符,而数组长度是不可变的
这样做的坏处是,损失效率,好处是,编译器可以共享字符。
实际应用中,很少改变字符串,更多的是比较,所以损失执行效率,提高系统性能。
如果确实要更改字符串,系统提供另外的类可以很方便的拼接字符串。
4 检测字符串是否相等
下面重新说明下==操作符的作用,这个操作符会得到一个布尔值,对或者错,比较什么呢?更为具体的是比较两边变量所指向的内存位置,如果是同一个位置那么,就是相等的,就返回true。
public class MyString {
public static void main(String[] args){
System.out.println("比较字符串String");
String a = "A";
String b = a;//这里面a和b变量都指向同一个字符串
String c = new String("A");//虽然c里面也是"A",但是,new关键字却是新建了一个字符串
if(a == b)
System.out.println("a == b");//会输出
if(a == c)
System.out.println("a == c");//内存不一样,不会输出
System.out.println("比较整型类Integer");
Integer x = 1;//自动装箱,把1变成Integer类了
Integer y = x;
Integer z = new Integer(1);
if(x == y)
System.out.println("x == y");//会输出
if(x == z)
System.out.println("x == z");//内存不一样,不会输出
System.out.println("比较基本数据类型int");
int i = x;//自动拆箱,Integer类的x里面的值取出来了
int j = i;
int k = new Integer(1);
if(i == j)
System.out.println("i == j");//会输出
if(i == k)
System.out.println("i == k");//会输出
System.out.println("比较基本数据类型int和整型类Integer");
int xx = 1;
Integer yy = xx;
Integer zz = new Integer(1);
if(xx == yy)//表面上比较的是两个类型,但是实际上Java自动把yy的值取出来,再比较的
System.out.println("xx == yy");//会输出
if(xx == zz)
System.out.println("xx == zz");//会输出
if(yy == zz)//两个都是Integer类型,Java就不取值比较了,所以不想等
System.out.println("yy == zz");//内存不一样,不会输出
}
}
从上面的例子,我们看出,Java编译器对基本数据类型是有优待的,只要有基本数据类型的==比较,就会取值比,但是关键是:String不是基本数据类型,所以String千万不能用==比较。
实际上,String的比较应该采用它的equals()方法。
System.out.println("比较字符串String");
String a = "A";
String b = a;//这里面a和b变量都指向同一个字符串
String c = new String("A");//虽然c里面也是"A",但是,new关键字却是新建了一个字符串
if(a == b)
System.out.println("a == b");//会输出
if(a == c)
System.out.println("a == c");//内存不一样,不会输出
if(a.equals(c))
System.out.println("a 和 c的值是一样的");//会输出
下面解释一下Java源码的equals()方法是怎么写的
public boolean equals(Object anObject) {
if (this == anObject) {
return true;//如果指向的内存一样,那么必然相等,不一样就继续比较呗
}
//如果传入的是String类型或其子类,那么还是有可能值是一样,就要继续判断
//如果类型都不一样,那么肯定不相等
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {//如果长度相等,则继续比较每一个值
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])//如果有某一位置的字符不一样,则不相等
return false;
i++;
}
return true;
}
}
return false;
}
很明显看出,equals()方法比较的是String的值,也正是我们想要的那种。
String类型还有个equalsIgnoreCase()方法,是忽略字母的大小写来进行比较的。
5 空串和null
String str = "";//这是空串,
if(str.length() == 0)
System.out.println("str的长度为0");//空串的长度就是0嘛
String str2 = null;//这个表明这个字符串,还没有指向任何字符串实例,没有指向嘛
String str3;//和上面语句一样一样的
if(str2 == null)//==是比较指向的,所以可以比较null
System.out.println("str2为null");
6 代码点和代码单元
每个字符用了一个代码点,但代码点有的用了一个代码单元,有的用了两个代码单元。
char[] ch = Character.toChars(0x1D546);
System.out.printf("U+1D546 高代理字符: %04x\n", (int)ch[0]);//d835
System.out.printf("U+1D546 低代理字符: %04x\n", (int)ch[1]);//dd46
String str = new String(ch);
System.out.println("字符是:" + str);
System.out.println("代码单元长度: " + str.length());//2
System.out.println("第0个代码单元是: " + str.charAt(0));//给定位置的代码单元,由于未定义,返回?
System.out.println("第1个代码单元是: " + str.charAt(1));//给定位置的代码单元,由于未定义,返回?
System.out.println("代码点数量: " + str.codePointCount(0, str.length()));//1
System.out.println("代码点是: " + str.codePointAt(0));//返回给定位置开始或结束的代码点,120134
str = "12345" + str + "67890";
System.out.println(str.substring(0, 6));//45?
System.out.println(str.substring(0, 7));//45?
System.out.println(str.substring(0, 8));//45��6
//遍历打出每一个代码点
int i = 0;
while(i < str.length()){
int cp = str.codePointAt(i);
System.out.println(cp);
if(Character.isSupplementaryCodePoint(cp))
i += 2;//如果cp所在的位置是代码点的第一部分,执行此处
else
i++;
}
关于这个知识点很难,我的建议是,如果你的字符串处理可能涉及到不常见的字符,请谨慎使用length()、chatAt()和subString()方法。
7 String类的API
- char charAt(int index)
返回指定位置的代码单元 - int codePointAt(int index)
返回指定位置的代码点 - int offsetByCodePoints(int startIndex, int cpCount)
以本字符串为基准,从指定位置startIndex开始,第cpCount个位置的代码点 - int compareTo(String other)
和其他的字符串按照字典顺序进行比较,如果本字符串在其他字符串前面,则返回一个负数,后面则返回一个正数,如果相等则返回0 - IntStream codePoints()
将本字符串,按照代码点流返回,再调用toArray()方法可以变成一个,代码点数组 - new String(int[] codePoints, int offset, int count)
对于指定的代码点数组,偏移offset,去count的长度,构建一个新的字符串 - boolean equals(Object other)
检测一个对象是否和本字符串相等 - boolean equalsIgnoreCase(String other)
检测一个字符串是否和本字符串相等,忽略大小写 - boolean startsWith(String prefix)
检测本字符串是否以一个指定字符串开始 - boolean endsWith(String suffix)
检测本字符串是否以一个指定字符串结束 - int indexOf(String str)
- int indexOf(String str, int fromIndex)
- int indexOf(int cp)
- int indexOf(int cp, int fromIndex)
从fromIndex(如果有的话)开始向后查找,返回指定字符串或代码点的序号 - int lastIndexOf(String str)
- int lastIndexOf(String str, int fromIndex)
- int lastIndexOf(int cp)
- int lastIndexOf(int cp, int fromIndex)
从fromIndex(如果有的话)开始向前查找,返回指定字符串或代码点的序号 - int length()
返回字符串的代码单元长度 - int codePointCount(int startIndex, int endIndex)
以本字符串为基准,返回指定范围(startIndex,endIndex-1)之间代码点的数量 - String replace(CharSequence oldString, CharSequence newString)
以本字符串为基准,将所有oldString替代为newString,构建新的字符串并返回 - String subString(int beginIndex)
- String subString(int beginIndex, int endIndex)
按指定范围构件子串 - String toLowerCase()
全部小写构建字符串 - String toUpperCase()
全部大写构建字符串 - String trim()
裁剪本字符串首尾的空格 - String join(Charquence delimiter, Charsequence… elements)
以指定分隔符delimiter连接所有字符集elements,构建成一个字符串
8 联网查看在线文档
9 构建字符串
如果要连接许多小的字符串,建议采用StringBuilder类。
StringBuilder sb = new StringBuilder();//构建一个StringBuilder对象
sb.append('I');//加入字符
sb.append(" ");//加入空格字符串
sb.append("love you!");//加入字符串
String state = sb.toString();//导出字符串
Java里面还有个StringBuffer类,基本上和StringBuilder相同,区别在于,效率低,但线程安全。
StringBuilder效率高,但线程不安全。
但是,大部分情况我我们并不需要跨线程构建字符串。所以StringBuilder使用的还是比较多的。
下面是StringBuilder的一些方法。
- StringBuilder()
构建StringBuilder对象,是空的。 - int length()
返回代码单元的长度 - StringBuilder append(String str)
加上一个字符串,并返回本身 - StringBuilder append(Char c)
加上一个字符,并返回本身 - StringBuilder appendCodePoint(int cp)
加上一个代码,并返回本身 - void setCharAt(int i, char c)
设置i位置为指定的字符 - StringBuilder insert(int offset, String str)
在指定位置插入字符串 - StringBuilder insert(int offset,Char c)
在指定位置插入字符 - StringBuilder delete(int startIndex, int endIndex)
删除指定范围内的数据 - String toString()
将内容导出为字符串