Java-String类
文章目录
- 写在前面
- 1 String类的常用方法
- 2. 字符串修改
-
- 2.1 StringBuilder和StringBuffer
- 2.2 面试题
写在前面
字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。在开发和校招中, 字符串也是常客, 所以这一章节也非常重要, 在本章节中, 我们需要掌握的是:
- 认识String类
- 了解String类的基本用法
- 熟练掌握String的常见操作
- 认识字符串常量池
- 认识 StringBuffer 和 StringBuilder
1 String类的常用方法
1.1 字符串的构造
String 类提供的构造方法有很多, 我们首先掌握以下常见的三种:
public static void main(String[] args) {// 使用常量串构造, 直接使用双引号引起来就行String s1 = "hello would";// 直接new一个String对象String s2 = new String("hello would");//使用字符数组进行构造char[] array = {'h','e','l','l','o',' ','w','o','u','l','d'};String s3 = new String(array);System.out.println(s1); System.out.println(s2);System.out.println(s3);}
这里我们虽然打印出的效果是一样的, 可是还是有一定区别,
注意
1.String 是引用类型, 内部并不储存字符串本身, 在String类的实现源码中, String类实例变量如下:
public static void main(String[] args) {// s1和s2引用的是不同的对象, s1和s3引用的同一对象String s1 = new String("hello");String s2 = new String("would");String s3 = s1;System.out.println(s1.length()); //获取字符串的长度System.out.println(s1.isEmpty()); //如果字符串的长度为0, 返回true, 否则返回false}
2.在Java中, 用双引号引起来的也是String类
比如: “hello”
System.out.println("hello".lenth());
1.2 String对象的比较
字符串的比较是比较常见的操作之一, 比如: 字符串比较,
Java提供4中比较方法:
1. 利用 == 比较是否引用同一对象
注意: 对于内置对象, ==比较的是内在的值, 而引用类型, == 比较的是引用中的地址
public static void main(String[] args) {int a = 10;int b = 20;int c = 10;System.out.println(a==b); // falseSystem.out.println(a==c); // trueString s1 = new String("hello");String s2 = new String("would");String s3 = new String("hello");String s4 = s1;System.out.println(s1==s2); //falseSystem.out.println(s1==s3); //falseSystem.out.println(s1==s4); //true}
2. 利用equals() 方法比较
首先我们看一下这个方法的源码
String类重写的父类Object的equals方法, Object中equals方法默认按照==比较, String重写了equals方法后, 就是按照上述源码中的方法比较, 下面我们具体来看:
public boolean equals(Object anObject) {
//1. 检测this 和anObject 是否为同一对象, 如果是返回trueif (this == anObject) {return true;}// 2. 检测anObject 是否为String类型的对象, 如果是继续比较, 否则返回false if (anObject instanceof String) {
// anObject 向下转型为String类型的对象String anotherString = (String)anObject;int n = value.length;
// 3. this 和 anObject两个字符串的长度是否相同, 是则继续比较, 否则返回trueif (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;
// 4. 按照字典序, 从前往后依次进行比较while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}
下面我们看一个实例:
public static void main(String[] args) {String s1 = new String("hello");String s2 = new String("hello");String s3 = new String("would");// s1 s2 s3 分别引用的是不同的对象, 所以==比较结果全是falseSystem.out.println(s1==s2); //falseSystem.out.println(s1==s3); //false//equals 比较, String对象中的各个字符//虽然s1和s2引用的不是一个对象, 但是它们两个对象中存放的内容是相同的, 所以输出true//s1和s3 不是一个对象, 而且两个对象存放的内容也不同, 所以输出falseSystem.out.println(s1.equals(s2)); //trueSystem.out.println(s1.equals(s3)); //false}
3. 利用compareTo 方法比较两个字符串的
与equals方法不同的是, equals返回的是boolean类型, compareTo方法返回的是int类型.
具体比较方式:
1.先按照字典序大小比较, 出现不等的字符, 直接返回这两个字符的大小差值.
2.如果前k个字符相等(k为这两个字符串的长度最小值),返回这两个字符串的长度差
public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("aBc");String s3 = new String("aD");String s4 = new String("abcdef");String s5 = new String("ab");System.out.println(s1.compareTo(s2)); //第二个字符不相等, 返回这两个字符的差值32System.out.println(s1.compareTo(s3)); //第二个字符不相等, 返回这两个字符的差值30System.out.println(s1.compareTo(s4)); //前k个字符都相等, 返回这两个字符串的长度差-3System.out.println(s1.compareTo(s5)); //前k个字符都相等, 返回这两个字符串的长度差1}
4.利用compareToIgnoreCase方法比较(忽略大小写)
public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("aBc");String s3 = new String("aD");String s4 = new String("abcdef");String s5 = new String("ab");System.out.println(s1.compareToIgnoreCase(s2)); //0System.out.println(s1.compareToIgnoreCase(s3)); //-2System.out.println(s1.compareToIgnoreCase(s4)); //-3System.out.println(s1.compareToIgnoreCase(s5)); //1}
1.3字符串查找
字符串查找也是字符串中非常常见的操作, String类提供的常见的查找方法:
方法 | 功能 |
---|---|
char charAt(int index) | 返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常 |
int indexOf(int ch) | 返回ch第一次出现的位置,没有返回-1 |
int indexOf(int ch, intfromIndex) | 从fromIndex位置开始找ch第一次出现的位置,没有返回-1 |
int indexOf(String str) | 返回str第一次出现的位置,没有返回-1 |
int indexOf(String str, intfromIndex) | 从fromIndex位置开始找str第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch) | 从后往前找,返回ch第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch, intfromIndex) | 从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1 |
int lastIndexOf(String str) | 从后往前找,返回str第一次出现的位置,没有返回-1 |
int lastIndexOf(String str, intfromIndex) | 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1 |
public static void main(String[] args) {String s = new String("aabbccdefgh");System.out.println(s.charAt(4)); //打印你所查找位置的上的元素cSystem.out.println(s.indexOf("b")); //打印你查找的元素第一次出现的位置2System.out.println(s.indexOf("b", 3)); //从你所选位置开始查找你所需元素 3System.out.println(s.indexOf("bcc"));//打印你查找的字符串第一次出现的位置3System.out.println(s.lastIndexOf("c")); //从后往前找,第一次出现的位置5System.out.println(s.lastIndexOf("b", 2));//从你所选位置从后往前找}
注意:上述方法都是实例方法
1.4转化
1. 数值和字符串的转化
public static void main(String[] args) {//数字转字符串String s1 = String.valueOf(1234); //intString s2 = String.valueOf(12.32); //doubleString s3 = String.valueOf(true); //boolean//字符串转数字int data1 = Integer.parseInt("1234");double data2 = Double.parseDouble("20.23");System.out.println(s1); System.out.println(s2);System.out.println(s3);System.out.println(data1);System.out.println(data2);}
2. 大小写转化
public static void main(String[] args) {String s1 = new String("HELLO");String s2 = new String("would");System.out.println(s1.toLowerCase()); //helloSystem.out.println(s2.toUpperCase()); //WOULD}
3. 字符串转数组
public static void main(String[] args) {String s1 = new String("HELLO WOULD");//字符串转数组char[] ch = s1.toCharArray();for (int i = 0; i < ch.length; i++) {System.out.println(ch[i]);}System.out.println("=============================");// 字符串转数字int data1 = Integer.parseInt("1234");double data2 = Double.parseDouble("12.14");System.out.println(data1+1); //1235System.out.println(data2+0.1);//12.24}
4. 格式化
public static void main(String[] args) {String s = String.format("%d-%d-%d", 2023, 04,18);System.out.println(s);}
1.5 字符串的替换
使用一个指定的字符串替换掉已有的字符串数据,方法如下:
方法 | 功能 |
---|---|
String replaceAll(String regex, String replacement) | 替换所有的指定内容 |
String replaceFirst(String regex, String replacement) | 替换首个内容 |
代码示例:
public static void main(String[] args) {//字符串的替换String str = "hello";System.out.println(str.replaceAll("l", "8"));System.out.println(str.replaceFirst("l", "8"));}
这里我们需要注意的是:字符串是一个不可变对象替换的时候不修改原来的字符串, 而是产生一个新的字符串
1.6 字符串拆分
就是将一个完整的字符串按照指定的分隔符划分为若干个子字符串.
方法 | 功能 |
---|---|
String[] split(String regex) | 将字符串全部拆分 |
String[] split(String regex, int limit) | 将字符串以指定的格式,拆分为limit组 |
实现字符串的拆分处理:
public static void main(String[] args) {//字符串的拆分String str = "hello would hello would";String[] result = str.split(" "); //按照空格拆分for (String s:result) {System.out.println(s);}}
字符串的部分拆分
public static void main(String[] args) {//字符串的部分拆分String str = "hello would hello would";String[] split = str.split(" ",3); //按空格分为三部分for (String s:split) {System.out.println(s);}
拆分是特别常见的操作, 我们一定要重点掌握,
还有一些特殊字符作为分隔符可能不能做出正确的拆分, 需要加上转义
拆分ip地址
String str = "192.168.1.1" ;
String[] result = str.split("\\\\.") ; //这里我们就要用到转义字符才能正确分割
for(String s: result) {System.out.println(s);
}
注意事项:
- 字符"|“, “.”, “*”, “+”; 前面加上”\\"
- 二如果是"“, 那就得写成”\\\\"
- 如果字符串中有多个分隔符, 用"|"作为连字符
多次拆分
public static void main(String[] args) {//字符串的多次拆分String str = "name=张三&age=18";String[] result = str.split("&");for (int i = 0; i < result.length; i++) {String[] temp = result[i].split("=");System.out.println(temp[0]+"="+temp[1]);}
1.7 字符串截取
从一个完整字符串截取出部分内容
方法 | 功能 |
---|---|
String substring(int beginIndex) | 从指定索引截取到结尾 |
String substring(int beginIndex, int endIndex) | 截取部分内容 |
public static void main(String[] args) {String str = "hellowould";System.out.println(str.substring(5)); //wouldSystem.out.println(str.substring(0, 5)); // hello}
注意:
- 索引从0开始
- 这里的写法是前闭后开, substring(0,5),表示包含0下标的值, 不包括5下标的字符
1.8 其他操作方法
方法 | 功能 |
---|---|
String trim() | 去掉字符串中的左右空格,保留中间空格 |
String toUpperCase() | 字符串转大写 |
String toLowerCase() | 字符串转小写 |
trim方法实例:
public static void main(String[] args) {String str = " hello would ";System.out.println("["+str+"]"); //[ hello would ]System.out.println("["+str.trim()+"]"); //[hello would]}
字符转大小写实例
public static void main(String[] args) {//字符串大小写转化String str = "12abc&^%*34DEF";System.out.println(str.toUpperCase()); //12ABC&^%*34DEFSystem.out.println(str.toLowerCase()); //12abc&^%*34def}
注意:
这两个函数只转换字母
1.9 字符串常量池
1.9.1 创建对象的思考
public static void main(String[] args) {String str1 = "hello";String str2 = "hello";String str3 = new String("hello");String str4 = new String("hello");System.out.println(str1==str2); //trueSystem.out.println(str1==str3); //falseSystem.out.println(str3==str4); //false}
上面我们创建方法类似, 为什么s1和s2 引用的是同一个对象, 而s3 和s4 不是呢?
在java程序中, 类似于:1, 2, 3, 4, 5, 6, 3.14 “hello” 等字面类型的常量会经常频繁的使用, 为了使程序运行的更快, 更节省内存,java为8种基本数据类型和String类都提提供了常量池.
为了节省存储空间和提高程序的运行效率, Java中引入了:
- Class文件常量池:每个Java源文件编译后生成 .class文件中会保存当前类中的字面常量和字符信息
- 运行时常量池:在.class文件被加载时, .class文件中的常量池被加载到内存中被称为运行时常量池, 运行时常量池每个类都有一份.
- 字符串常量池
2. 字符串修改
在这里我们首先要知道:
- String类在设计时就是不可改变的,String类实现描述就已经说明了
- String类中的字符实际保存在内部维护的value字符数组中
- 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
- final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内
容是可以修改的(返回创建的新对象)。
那为什么我们还要谈字符串修改呢?
原因是:我们应该尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率
非常低下。
public static void main(String[] args) {String str = "hello";str += "would";System.out.println(str); // hellowould}
这种方法不推荐使用, 其效率非常低下, 中间创建了许多临时对象
下面我们做一个对比
public static void main(String[] args) {//传统修改字符串的方式long start = System.currentTimeMillis(); //开始时间String str = "0";for (int i = 0; i < 100000; i++) {str += i;}long end = System.currentTimeMillis(); //结束时间System.out.println(end-start); //修改完用时:18619//StringBufferstart = System.currentTimeMillis();StringBuffer str1 = new StringBuffer("0");for (int i = 0; i < 100000; i++) {str1.append(i);}end = System.currentTimeMillis();System.out.println(end-start); //修改完用时:2//StringBuilderstart = System.currentTimeMillis();StringBuilder str2 = new StringBuilder("0");for (int i = 0; i < 100000; i++) {str2.append(i);}end = System.currentTimeMillis();System.out.println(end-start); //修改完用时:1}
在这里我们可以看出, 在对String类进行修改的时候, 效率是非常慢的, 因此我们要尽量对String的直接修改, 如果要修改, 建议使用StringButter和StringBuilder
2.1 StringBuilder和StringBuffer
由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大
部分功能是相同的,下面介绍 StringBuilder常用的一些方法,其它需要用到了大家可参阅StringBuilder在线文档
方法 | 功能 |
---|---|
StringBuff append(Stringstr) | 在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、 double、float、int、long、Object、String、StringBuff的变量 |
char charAt(int index) | 获取index位置的字符 |
int length() | 获取字符串的长度 |
int length() | 获取字符串的长度 |
int capacity() | 获取底层保存字符串空间总的大小 |
mininmumCapacity) | 扩容 |
void setCharAt(int index,char ch) | 将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, intfromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastIndexOf(String str, | |
int fromIndex) | 从fromIndex位置开始找str最后一次出现的位置 |
StringBuff insert(intoffset, String str) | 在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer | |
deleteCharAt(int index) | 删除index位置字符 |
StringBuffer delete(intstart, int end) | 删除[start, end)区间内的字符 |
StringBuffer replace(int | |
start, int end, String str) | 将[start, end)位置的字符替换为str |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
String substring(int | |
start,int end) | 将[start, end)范围内的字符以String的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照String的方式返回 |
public static void main(String[] args) {//字符串修改的应用StringBuffer sb1 = new StringBuffer("hello");StringBuffer sb2 = sb1;sb1.append(' '); //尾插sb1.append("would");System.out.println(sb1); //hello wouldsb1.append(1234);System.out.println(sb1); //hello would1234System.out.println(sb1==sb2); //trueSystem.out.println(sb2); //hello would1234System.out.println(sb1.charAt(0)); //获取0位置上的字符 hSystem.out.println(sb1.length()); //获取字符串的有效长度System.out.println(sb1.capacity()); //获取底层数组的总大小sb1.setCharAt(0,'H'); // 设置任意位置上的字符sb1.insert(0,"hello would"); //设置任意位置的字符,可一改多System.out.println(sb1);sb1.append("hello would");System.out.println(sb1.indexOf("hello")); //获取hello第一次出现的位置System.out.println(sb1.lastIndexOf("hello"));// 获取hello最后出现的位置System.out.println(sb1); //输出sb1 hello wouldHello would1234hello wouldsb1.delete(0,5); //删除[0,5)的上的字符String ret = sb1.substring(3,6); //截取[3.6)上的字符, 返回给retSystem.out.println(sb1); // wouldHello would1234hello wouldsb1.reverse(); //字符串逆转System.out.println(sb1); //dluow olleh4321dluow olleHdluowsb1.toString(); //将StringBuffer以String的方式返回System.out.println(sb1);}
从上述例子可以看出:String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可
以修改。频繁修改字符串的情况考虑使用StringBuilder。
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
StringBuilder变为String: 调用toString()方法。
2.2 面试题
- String、StringBuffer、StringBuilder的区别
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
- StringBuffer与StringBuilder大部分功能是相似的
- StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操
作