目录
简单认识String类
Java里一切皆对象,作为应用广泛的字符串,Java专门为其提供了String类。
String是引用类型,内部并不存储字符串本身,观察String类的源码:
可以知道String类中包含 value[] 和 hash 两个成员属性,字符串实际保存在char类型的数组里
用String类创建的对象存放的是对应的地址:
简单认识了String类后我们就可以来了解如何使用它了~
String类的常用方法
1.字符串的构造
字符串的构造有以下3种常用方式:
●使用常量串构造
String s = "hello";
●直接new一个String的对象
String s = new String("hello");
●使用字符数组进行构造
char[] ch = {'h', 'e', 'l', 'l', 'o'}; String s = new String(ch);
2.字符串的比较
字符串的比较有以下四种方式:
●使用==比较是否引用同一个对象
我们知道==比较的是变量中的值,字符串是引用类型==比较的是引用中的地址,故通过==可以比较是否是同一个变量
public class Test { public static void main(String[] args) { String s1 = new String("hello"); String s2 = new String("hello"); String s3 = s1; System.out.println(s1 == s2);//s1和s2存放两个不同对象的地址,故输出false System.out.println(s1 == s3);//s1和s3存放同一对象的地址,故输出true } }
●使用boolean equals(Object anObject)方法按照字典序(字符大小顺序)进行比较
String类中重写了父类Object中的equals方法,Object中equals默认按照==进行比较,重写后的equals方法先后按照:为同一个对象返回true ➞ 不是String类型的对象返回false ➡ 长度不同返回false ➡ 按字典序从前往后逐个字符进行比较,遇到不同返回false,都相同返回true
使用equals方法可以比较字符串的内容是否相等
public class Test { public static void main(String[] args) { String s1 = new String("hello"); String s2 = new String("hello"); String s3 = new String("world"); String s4 = s1; System.out.println(s1.equals(s2));//s1和s2虽然是两个不同的对象,但两个对象中放置的内容相同,输出true System.out.println(s1.equals(s3));//s1和s3是两个不同的对象,而且两个对象中放置的内容不相同,输出false System.out.println(s1.equals(s4));//s1和s4是两个相同对象,输出true } }
●使用int compareTo(String s)方法按照字典序进行比较
compareTo方法是先按照字典序进行比较,遇到不相等的字符则返回两字符大小的差值,若字符相等,长度不相等,则返回两字符串长度的差值,完全相等返回0、
使用compareTo也可以比较字符串内容是否相等
public class Test { public static void main(String[] args) { String s1 = new String("hello"); String s2 = new String("hello"); String s3 = new String("world"); String s4 = new String("hello world"); System.out.println(s1.compareTo(s2));//s1和s2两个对象中放置的内容相同,输出0 System.out.println(s1.compareTo(s3));//s1和s3两个对象中放置的内容不相同,返回第一对不相等字符('h'和'w')的差值 System.out.println(s1.compareTo(s4));//s1和s4两个对象中放置的内容程包含关系,返回两字符串长度差值 } }
●使用int compareToIgnoreCase(String str)方法按照字典序进行比较
compareToIgnoreCase方法与 compareTo 方式相似,但是忽略大小写比public class Test { public static void main(String[] args) { String s1 = new String("abc"); String s2 = new String("ac"); String s3 = new String("ABc"); String s4 = new String("abcdef"); System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值 -1 System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0 System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3 } }
3.字符串的查找
●char charAt(int index)
用于返回 index 位置上字符,如果 index 为负数或者越界,抛出IndexOutOfBoundsExceptio异常public class Test { public static void main(String[] args) { String s = new String("abcdabcd"); System.out.println(s.charAt(2));//输出s的2下标所对应的值:c } }
●int indexOf(int ch)
用于返回ch第一次出现的位置,没有返回-1
public class Test { public static void main(String[] args) { String s = new String("abcdabcd"); System.out.println(s.indexOf('c'));//输出'c'在s中从前往后第一次出现的位置:2 } }
●int indexOf(int ch, int fromIndex)
用于从fromIndex位置开始找ch第一次出现的位置,没有返回-1
public class Test { public static void main(String[] args) { String s = new String("abcdabcd"); System.out.println(s.indexOf('c', 3));//输出从s的3下标开始往后第一次出现'c'的位置:6 } }
●int indexOf(String str)
用于返回 str 第一次出现的位置,没有返回 -1public class Test { public static void main(String[] args) { String s = new String("abcdabcd"); System.out.println(s.indexOf("bc"));//输出"bc"在s中从前往后第一次出现的位置:1 } }
●int indexof(String str, int fromIndex)
用于从 fromIndex 位置开始找 str 第一次出现的位置,没有返回 -1public class Test { public static void main(String[] args) { String s = new String("abcdabcd"); System.out.println(s.indexOf("bc", 3));//输出从s的3下标开始往后第一次出现"bc"的位置:5 } }
●int lastIndexOf(int ch)
用于从后往前找,返回 ch 第一次出现的位置,没有返回 -1public class Test { public static void main(String[] args) { String s = new String("abcdabcd"); System.out.println(s.lastIndexOf('c'));//输出s中从后往前第一次出现'c'的下标 } }
●int lastIndexOf(int ch, int fromIndex)
用于从 fromIndex 位置开始找,从后往前找 ch 第一次出现的位置,没有返回-1public class Test { public static void main(String[] args) { String s = new String("abcdabcd"); System.out.println(s.lastIndexOf('c', 3));//输出从s的3下标从后往前第一次出现'c'的位置:2 } }
●int lastIndexOf(String str)
用于从后往前找,返回str第一次出现的位置,没有返回-1
public class Test { public static void main(String[] args) { String s = new String("abcdabcd"); System.out.println(s.lastIndexOf("bc"));//输出s中从后往前第一次出现"bc"的位置:5 } }
●int lastIndexOf(String str, int fromIndexOf)
用于从 fromIndex 位置开始找,从后往前找 str 第一次出现的位置,没有返回-1public class Test { public static void main(String[] args) { String str = "abcdabcd"; System.out.println(str.lastIndexOf("bc", 3));//输出从s的3下标开始往前第一次出现"bc"的位置:1 } }
4.字符串的转换
●字符串转数字
public class Test { public static void main(String[] args) { int data = Integer.parseInt("123"); System.out.println(data + 1);//输出124 } }
●数字转字符串
public class Test { public static void main(String[] args) { String s = String.valueOf(123); System.out.println(s);//输出123 } }
●大写字母转小写字母
public class Test { public static void main(String[] args) { String s1 = "aBc"; String s2 = s1.toLowerCase();//由于字符串是不可变对象,故该方法返回一个新对象,不修改原对象 System.out.println(s2);//输出abc System.out.println(s1);//输出aBc } }
●小写字母转大小字母
public class Test { public static void main(String[] args) { String s1 = "aBc"; String s2 = s1.toUpperCase();//由于字符串是不可变对象,故该方法返回一个新对象,不修改原对象 System.out.println(s2);//输出ABC System.out.println(s1);//输出aBc } }
●字符串转数组
public class Test { public static void main(String[] args) { String s = "abc"; char[] ch = s.toCharArray(); //输出a b c for (char x: ch) { System.out.print(x + " "); } } }
●数组转字符串
public class Test { public static void main(String[] args) { char[] ch = {'a', 'b', 'c'}; String s = new String(ch); System.out.println(s);//输出abc } }
●格式化
public class Test { public static void main(String[] args) { String s = String.format("%d-%d-%d", 2020, 10, 6); System.out.println(s);//输出2020-10-6 } }
5.字符串的替换
●替换所以指定内容
public class Test { public static void main(String[] args) { String s1 = "abcdabcd"; String s2 = s1.replaceAll("b", "c");//由于字符串是不可变对象,故该方法返回一个新对象,不修改原对象 System.out.println(s2);//输出accdaccd System.out.println(s1);//输出abcdabcd } }
●替换首个内容
public class Test { public static void main(String[] args) { String s1 = "abcdabcd"; String s2 = s1.replaceFirst("b", "c");//由于字符串是不可变对象,故该方法返回一个新对象,不修改原对象 System.out.println(s2);//输出accdabcd System.out.println(s1);//输出abcdabcd } }
6.字符串的拆分
●将字符串全部拆分
public class Test { public static void main(String[] args) { String s = "hello-world-hello-everyone"; String[] ch = s.split("-"); for (String x : ch) { System.out.print(x + " ");//输出hello world hello everyone } } }
●将字符串以指定格式拆分为limit组
public class Test { public static void main(String[] args) { String s = "hello-world-hello-everyone"; String[] ch = s.split("-", 2); for (String x : ch) { System.out.print(x + " ");//输出hello world-hello-everyone } } }
注:有些特殊字符('|','*','+'等)作为分割符需要加上转义才能正确分割
7.字符串的截取
●从指定索引截取到结尾
public class Test { public static void main(String[] args) { String s1 = "abcd"; String s2 = s1.substring(2);//由于字符串是不可变对象,故该方法返回一个新对象,不修改原对象 System.out.println(s2);//输出cd System.out.println(s1);//abcd } }
●截取部分内容
public class Test { public static void main(String[] args) { String s1 = "abcd"; String s2 = s1.substring(2, 3);//截取范围为[2,3),且由于字符串是不可变对象,故该方法返回一个新对象,不修改原对象 System.out.println(s2);//输出c System.out.println(s1);//abcd } }
8.字符串的其他操作方法
●去掉字符串中的左右空格,保留中间空格
public class Test { public static void main(String[] args) { String s1 = " a b c "; String s2 = s1.trim();//由于字符串是不可变对象,故该方法返回一个新对象,不修改原对象 System.out.println(s2);//输出a b c System.out.println(s1);//输出 a b c } }
字符串常量池
字符串常量池是Java为了使程序的运行速度更快,更省内存而提供的。
在创建sting对象的时候就会用到字符串常量池,不同方式的创建过程对字符串常量池的处理方式也不同。● 直接使用字符串常量进行赋值public class Test { public static void main(String[] args) { String s1 = "hello"; String s2 = "hello"; } }
当字节码文件加载时,"hello"就会创建好并保存在字符串常量池中,当使用String s1 = "hello"创建对象时,先在字符串常量池中寻找该字符串,找到后将字符串引用赋值给s1。
如下图所示:
● 通过new创建String对象public class Test { public static void main(String[] args) { String s1 = "hello"; String s2 = "hello"; String s3 = new String("world"); String s4 = new String("world"); } }
使用new创建Sting对象也会将"world"创建创建好并保存在字符串常量池中,但每个new都会再创建一个新的对象。如下图所示:注:我们可以使用intern方法手动将创建的String对象添加到常量池中。(如: s1.intern() ;/*调用之后,会将 s1 对象的引用放入到常量池中*/ )
字符串的不可变性
我们知道String是一种不可变对象. 字符串中的内容是不可改变。那为什么字符串是不可变的呢?
通过观察源码可以看到:
String 类被final修饰,表明它不能被继承;引用变量 value 被 final 修饰表明它不能引用其他对象;而引用变量value被private修饰则表明它不能在类外使用,故字符串是不可变对象。
Java使字符串设计成不可变对象有以下几点好处:、
1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.2. 不可变对象是线程安全的.3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中