《JAVASE系列》String 类
文章目录
前言:
本章学习内容:
- 熟悉String类的基本用法
- 掌握String类的库方法
- 认识字符串常量池
- 认识StringBuffer与StringBuilder
参考书籍:《java核心卷1》
你若盛开,清风自来。
1. String类的基本用法
1.1 字符串构造
字符串的构造方式很多,常用的一般为以下三种:
public class Main {
public static void main(String[] args) {
//直接赋一个常量值
String s1 = "hello";
//直接new一个String 对象再赋值给name2
String s2 = new String("hello");
//使用字符数组进行构造
char[] arr = new char[]{'h','e','l','l','o'};
String s3 = new String(arr);
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}
}
1.2 String是引用类型
String是引用类型,内部并不存储字符串本身
查看String 的源码:
我们不难看出,String类的构造方法将传进来字符串是以字符数组存储在String 类中的value字符数组中,所以String内部并不是存储字符串本身,而是拷贝这个字符串存储在字符数组value中。
String类的构造方法并不只有一个,例如s3就调用了另一个构造方法:
存储的过程如下:
1.3 String对象的比较
1.3.1 通过 “==” 比较
由于String类型是引用类型
所以: == 比较是否引用同一个对象
public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = s1;
System.out.println(s1==s3);
System.out.println(s1==s2);
}
}
运行结果:
s3与s1都指向“hello”这个string 对象,二者存储的地址相同,所以二者相等
s1指向“hello”对象,s2指向“world”对象,二者存储的地址不同,所以不相等
至于以下情况:
public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1==s2);
}
}
运行结果:
为什么是true:
与字符串的常量池有关。后续介绍
1.3.2 通过equals比较
equals方法会帮我们比较两个字符串类型变量的内容是否相同,相同返回true,不同返回flase
源码分析:
equals会先比较两个字符串引用的地址是否相同,如果地址相同,则内容必然相同,返回true。
如果两个字符串的地址不同,会一个一个字符得去比较,如果有一个字符不相等,则返回false,全部都相同返回true。
public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1.equals(s2));
}
}
运行结果:
1.3.3 通过comparTo比较
compareTo源码分析:
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:
- 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
- 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
1.3.4 忽略大小写的比较
equalsIgnoreCase 与 equal 类似,但是忽略大小写的比较
compareToIgnoreCase 与 compare 类似,但是忽略大小写的比较
2.String类常用方法
2.1 字符串查找
字符串查找是字符串中非常常见的操作,String类提供的常用查找的方法:
2.1.1 char charAt
charAt(int index)
返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常。
代码演示:
public class Main {
public static void main(String[] args) {
String str = "helloworld";
for (int i = 0; i < str.length(); i++) {
System.out.print(str.charAt(i)+" ");
}
}
}
运行结果:
2.1.2 int indexOf
1 int indexOf(int ch)
返回ch第一次出现的位置,没有返回 -1
代码演示:
public class Main {
public static void main(String[] args) {
String str = "helloworld";
int a = str.indexOf("e"); //得到第一次出现e的下标位置
System.out.println(a);
}
}
运行结果:
2 int indexOf(int ch,int fromIndex)
从fromIndex位置开始找ch第一次出现的位置,没有返回 -1
代码演示:
public class Main {
public static void main(String[] args) {
String str = "helloworld";
int a1 = str.indexOf("o",3); //得到下标为3之后 出现o的下标位置
int a2 = str.indexOf("o",5); //得到下标为5之后 出现o的下标位置
System.out.println(a1);
System.out.println(a2);
}
}
运行结果:
3 int indexOf(String str)
返回字符串 str 第一次出现的位置,没有返回-1
代码演示:
public class Main {
public static void main(String[] args) {
String str = "helloworld";
int a1 = str.indexOf("llo");
int a2 = str.indexOf("rld");
System.out.println(a1);
System.out.println(a2);
}
}
运行结果:
4 int indexOf(String str,int fromIndex)
从fromIndex位置开始找字符串 str 第一次出现的位置,没有返回-1
代码演示:
public class Main {
public static void main(String[] args) {
String str = "helloworld";
int a1 = str.indexOf("llo",3);
int a2 = str.indexOf("rld",3);
System.out.println(a1);
System.out.println(a2);
}
}
运行结果:
2.1.3 int lastIndexOf
与indexOf一样,但是是从字符串最后开始查找。
int lastIndexOf(int ch)
从后往前找,返回ch第一次出现的位置,没有返回-1
int lastIndexOf(int ch, int fromIndex)
从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1
int lastIndexOf(String str)
从后往前找,返回str第一次出现的位置,没有返回-1
int lastIndexOf(String str, int fromIndex)
从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返
回-1
2.2 字符串转化
2.2.1 数值和字符串转化 String.valueOf
public class Main {
public static void main(String[] args) {
String str1 = String.valueOf(1234);
String str2 = String.valueOf(12.34);
String str3 = String.valueOf(true);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
}
}
运行结果:
2.2.2 大小写转化 str.toUpperCase与str.toLowerCase
public class Main {
public static void main(String[] args) {
String str = "HeLLo";
String str1 = str.toLowerCase();
String str2 = str.toUpperCase();
System.out.println(str1);
System.out.println(str2);
}
}
运行结果:
2.2.3 字符串转数组 str.toCharArray
public class Main {
public static void main(String[] args) {
String str = "hello";
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.print(chars[i]+" ");
}
}
}
运行结果:
2.2.4 格式化 String.formate
public class Main {
public static void main(String[] args) {
String s = String.format("%d-%d-%d",2022,4,18);
System.out.println(s);
}
}
运行结果:
2.3 字符串替换
使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
- String replaceAll(String regex, String replacement) 替换所以内容
- String replaceFirst(String regex, String replacement) 替换首个内容
public class Main {
public static void main(String[] args) {
String str = "helloworld";
System.out.println(str.replaceAll("l","xixi"));
System.out.println(str.replaceFirst("l","xixi"));
}
}
运行结果:
也就是说,replaceAll只要字符串中有regex的内容,每份内容都会被替代为replacement的内容
而replaceFirst是只替换掉字符串regex的第一份内容为replacement
2.4 字符串拆分
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。可用方法如下:
- String[] split(String regex) 拆分所有内容
- String[] split(String regex, int limit) 拆分成limit组
代码示例:
public class Main {
public static void main(String[] args) {
String str = "hello world yes hi";
String[] arr1 = str.split(" ");
String[] arr2 = str.split(" ",2);
for (String S:arr1) {
System.out.println(S+" ");
}
System.out.println();
for (String S:arr2) {
System.out.println(S+" ");
}
}
}
运行结果:
注意事项:
注意事项:
- 字符"|“,”*“,”+"都得加上转义字符,前面加上 “\” .
- 而如果是 “” ,那么就得写成 “\\” .
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符.
2.5 字符串截取
从一个完整的字符串之中截取出部分内容。可用方法如下:
- String substring(int beginIndex) 从指定索引截取到结尾
- String substring(int beginIndex, int endIndex) 截取部分内容
public class Main {
public static void main(String[] args) {
String str = "helloworld";
System.out.println(str.substring(3));
System.out.println(str.substring(3,6));
}
}
运行结果:
2.6 去掉字符串左右的空格
String trim() 去掉字符串中的左右空格,保留中间空格
public class Main {
public static void main(String[] args) {
String str = " helloworld ";
System.out.println(str);
System.out.println(str.trim());
}
}
运行结果:
了解String类的内部常量:
String类被final修饰,表明该类不能被继承.
为什么String类为不可修改字符串:
在上面的代码中,我们可以看到value值是被private修饰的,也就是外部类是无法修改value的值,并且被final修饰,也就意味着当value值被赋值成功后,在String类中也无法再一次得修改这个值.(保证字符内容不可变)
在任何涉及到字符串的截取修改比较等等的方法,都会创建出新的String对象,例如:
3.字符串常量池:
3.1什么是池:
池是编程中十分常见的用来提升效率的方式,在未来的学习中会遇到许多类似的池化技术,例如:内存池,线程池,数据库连接池,Class文件常量池,运行时常量池…
此处我们着重了解字符串常量池.
3.2字符串常量池(StringTable)
字符串常量池在JVM中是一个StringTable类,实际上是一个固定大小的HashTable.
在java8版本中,字符串常量池的位置位于堆中.大小可设置,有范围限制,最小是1009.
如何将字符串存入字符串常量池的:
-
JVM 中 字符串常量池是只有一个的,并且作为全局共享.
-
一开始的时候,字符串常量池是为空,随着程序的运行,String类对象的不断创建,字符串常量池的元素会越来越多.
-
随着类的加载,字节码文件的常量池也被加载到JVM中,(运行时常量池),并且会将字符串常量保存在字符串常量池中去.
也就是说:字符串常量池的内容来自于:运行时常量池,程序的动态添加.
3.2String对象的不同创建方式在字符串常量池中的反应
直接赋值:
public static void main(String[] args){
String s1 = "hello";
String s2 = "hello";
System.out.println(s1==s2);//结果是true
}
为什么结果为true,按照上述的讲解,String类是引用对象,按理说所存的地址是不同的.
其主要原因:
-
编译时,字节码文件加载,会先将hello字符串加载字符串常量池中去.
-
当创建s2时,JVM会先去字符串常量池中匹配是否存在与s2字符串内容相同的对线,如果存在,则直接将该字符串的引用赋值给s2.
使用new创建String类对象
public static void main(String[] args){
String s3 = new String("world");
String s4 = new String("world");
System.out.println(s3==s4);//结果是flase
}
会先讲字符串的内容在常量池中检查,如果常量池中没有,则存入字符串常量池中,
对于new 的对象而言,会在堆中生成一个对象,这个对象是有自己的地址,但是value的内容会指向目标字符串.
图解:
4.简单了解StringBuffer和StirngBuilder.
4.1介绍StirngBuffer的方法:
StringBuff append(String str) | 在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、 double、float、int、long、Object、String、StringBuff的变量 |
---|---|
char charAt(int index) | 获取index位置的字符 |
int length() | 获取字符串的长度 |
int capacity() | 获取底层保存字符串空间总的大小 |
void ensureCapacity(int mininmumCapacity) | 扩容 |
void setCharAt(int index, char ch) | 将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastIndexOf(String str, int fromIndex) | 从fromIndex位置开始找str最后一次出现的位置 |
StringBuff insert(int offset, String str) | 在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer deleteCharAt(int index) | 删除index位置字符 |
StringBuffer delete(int start, 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的方式返回 |
4.2String类与StirngBuffer,StirngBuilder的区别:
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
- StringBuffer与StringBuilder大部分功能是相似的 .
- StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
总结:
String类是做题中常用的类,需要着重学习.对于常量池的概念要清楚…
加油加油!!!