文章目录
String类
String类的简单认识
String, 即字符串类型;在java代码中应用广泛,为了符合java面向对象的核心思想,java语言提供了String类;具体体现在代码中,就是当被双引号引起来时,代表一个字符串。在java中,不存在字符串结束标志的说法,一般判断字符串是否结束是通过字符串的长度来判断的;
确定字符串长度的函数是 length( );
public class Test2 {
public static void main(String[] args) {
String str="hello";
System.out.println(str.length());
System.out.println("hello".length()); //也可以直接通过字符串调用
}
}
字符串的构造
字符串的构造方式有许多,但是最常用的主要有3种方式:
- 直接使用常量字符串;
String str="hello";
这种构造方式实际只在内存中开辟了一块空间,将双引号引起来的内容保存在字符串常量池中;
- 使用new String创建;
String str=new String("hello");
这种构造方式在内存中会开辟2块空间,即“hello”保存在字符串常量池中,同时new String 也是在堆上开辟了一块内存;
- 使用字符数组进行构造;
char [] chars= {'h','e','l','l','o'};
String str=new String(chars);
这是这种构造方式的源码:
可以看到,其实是利用copyOf又开辟了一块数组空间
这种构造方式也是开辟了2块内存,即首先在堆上创建一个String对象,然后利用copyof重新开辟数组空间,将参数字符串数组中内容拷贝到String对象中;
String的内在存储形式
观察String的源码:
这是String类的成员属性,包含了2个部分,即value和hash,其中字符串的具体内容是存储在value部分的;因此String是一种引用类型,内部并不存储字符串本身;
字符串的比较
- 使用==比较2个字符串的地址是否一致,即是否指向同一个对象;
- 使用equals逐个比较2个字符串中的字符是否一致,返回的是boolean类型;
- 使用compareTo方法比较2个字符的差值,返回int 类型;
- 使用equalsIgnoreCase( )或compareToIgnoreCase( )忽略大小写进行比较;
public static void main(String[] args) {
String str1="hello";
String str2="hello";
//比较2个字符串是否指向同一个对象
System.out.println(str1==str2);
String str3="hello";
String str4="world";
//逐个比较2个字符串的字符是否一致
System.out.println(str3.equals(str4));
String str5="hello";
String str6="aello";
//进行字符串的大小比较,返回差值
System.out.println(str5.compareTo(str6));
String str9="hello";
String str10="hel";
//如果前k个字符相等(k为两个字符长度最小值),返回两个字符串的长度差值
System.out.println(str9.compareTo(str10));
String str7="hello";
String str8="Hello";
//忽略大小写,比较方法与equals()一致
System.out.println(str7.equalsIgnoreCase(str8));
///忽略大小写,比较方法与compareTo()一致
System.out.println(str7.compareToIgnoreCase(str8));
}
字符串查找
public static void main(String[] args) {
String s = "ababcdddcbcdbdcdbc";
//charAt(int index) 返回index位置上的字符
System.out.println(s.charAt(3)); //b
//indexOf(int ch) 返回ch第一次出现的位置,没有返回-1
System.out.println(s.indexOf('c')); //4
//indexOf(int ch, int fromIndex) 从fromIndex位置开始找ch第一次出现的位置,没有返回-1
System.out.println(s.indexOf('c', 5)); //8
//indexOf(String str) 返回str第一次出现的位置,没有返回-1
System.out.println(s.indexOf("bc")); //3
//indexOf(String str, int fromIndex) 从fromIndex位置开始找str第一次出现的位置,没有返回-1
System.out.println(s.indexOf("bd", 8)); //12
//lastIndexOf(int ch) 从后往前找,返回ch第一次出现的位置,没有返回-1
System.out.println(s.lastIndexOf('c')); //17
//lastIndexOf(int ch, int fromIndex) 从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1;
System.out.println(s.lastIndexOf('c', 10)); //10
// lastIndexOf(String str) 从后往前找,返回str第一次出现的位置,没有返回-1
System.out.println(s.lastIndexOf("db")); //15
//lastIndexOf(String str, int fromIndex) 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1
System.out.println(s.lastIndexOf("cb", 8)); //8
}
有关字符串的转化
数值与字符串的相互转化
public static void main(String[] args) {
//字符串转数字
String str="0730";
//Integer、Double是java中的包装类型,根据转化的数值进行选择
System.out.println(Integer.valueOf(str)); //730
System.out.println(Integer.valueOf("5678")); //5678
System.out.println(Double.valueOf("89.67")); //89.67
//数字转字符串
System.out.println(String.valueOf(8765)); //8765
System.out.println(String.valueOf(90.09)); //90.09
System.out.println(String.valueOf(true)); //true
System.out.println(String.valueOf('A')); //A
}
大小写转换
public static void main(String[] args) {
String str="hello";
String str1="HeLLo";
//小写转大写
System.out.println(str.toUpperCase()); //HELLO
//大写转小写
System.out.println(str1.toLowerCase()); //hello
}
大小写转换只针对字母;
字符串转数组
public static void main(String[] args) {
//字符串转数组
String str="hello";
char[] chars=str.toCharArray();
System.out.println(Arrays.toString(chars)); // [h, e, l, l, o]
//数组转字符串
char [] ch={'h','e','l','l','o'};
String str1=new String(ch);
System.out.println(str1); //hello
}
格式化
public static void main(String[] args) {
String s = String.format("%d-%d-%d", 2022, 7,30);
System.out.println(s);
}
字符串的替换
public static void main(String[] args) {
String str="asddsaasdfdsa";
//替换掉字符串中所有的指定内容
System.out.println(str.replace('a','p')); //psddsppsdfdsp
//替换字符串中指定的首个字符
System.out.println(str.replaceFirst("s","m")); //amddsaasdfdsa
}
字符串的拆分
全部划分
public static void main(String[] args) {
String str="welcome to new world";
//将所有字符串按照指定的分隔符拆分
String [] s=str.split(" ");
for (String st:s) {
System.out.println(st);
}
}
分组划分:
public static void main(String[] args) {
String str = "welcome to new world";
//根据规定的分隔符和分割后的组数划分(按顺序划分,不是平均分)
String[] s = str.split(" ", 2);
for (String s1 : s) {
System.out.println(s1);
}
}
特殊分隔符需要进行转义
public static void main(String[] args) {
String str="192.168.1.2" ;
String [] s=str.split("\\.") ;//一些特殊的分隔符需要进行转义
for (String s1 : s) {
System.out.println(s1);
}
}
特殊分隔符的转义方法:
- 字符 " | " , " * " , " + "都得加上转义字符,前面加上 " \ " ;
- 如果是 " \ " ,那么就得写成 " \\ " ;
多次划分;
public static void main(String[] args) {
String str="1234&987=wer";
String [] s=str.split("&");
for (String s1:s) {
String [] str1=s1.split("=");
for (String s2:str1) {
System.out.println(s2);
}
}
}
,
需要多个分隔符同时划分时,使用“ | ”;
public static void main(String[] args) {
String str="hello,welcome to China";
String [] s=str.split(",| ");
for (String x:s) {
System.out.println(x);
}
}
字符串的截取
public static void main(String[] args) {
String str="hello my friend";
//从指定索引截取到字符串结束
System.out.println(str.substring(6));
//截取从启始索引到结束索引的所有字符(左闭右开,不包含结束索引位置的字符)
System.out.println(str.substring(4,9));
}
字符串的左右空格
public static void main(String[] args) {
String str=" h e l l o ";
System.out.println(str.trim());
System.out.println(str);
}
字符串常量池
前面提到,java中凡是双引号引起来的内容都是保存在字符串常量池中的,那么什么是字符串常量池呢?
字符串常量池
“池”:是编程中一种常见的,可以提高效率的方式,将程序当中,经常频繁使用的常量保存在池中,可以有效地提高程序的运行速度,同时节省内存,存放字符串常量的池就是字符串常量池,字符串常量池本质上是StringTable类,是一个固定大小的HashTable。
关于字符串常量池;
- JVM中字符串常量池只有一份,全局共享;
- 字符串常量池中的元素随着程序的不断运行逐渐增多,一开始是空的;
再谈字符串的创建方式
- 直接使用字符串常量赋值
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true
}
- 通过new创建String类对象
public static void main(String[] args) {
String s1=new String("hello");
String s2=new String("hello");
System.out.println(s1==s2); //false
}
- intern()方法
public static void main(String[] args) {
char [] chars={'h','e','l','l','o'};
String str=new String(chars);
//intern()方法 手动将str对象的引用放入常量池中
str.intern();
String str1="hello";
System.out.println(str==str1);//true
}
如果不使用该方法,输出的结果是false;当使用了该方法,就是把str对象的引用手动地放到了常量池中,后续str1创建时,首先到常量池中寻找,最后结果为true ;
字符串的不可变性
再次观察String的源码:
String类被final修饰,表明这个类是不可以被继承的;
value被final修饰,表明value的值是不可以被修改的,但是这里不可修改的意思是不可以再value值的原有内存空间上修改,但如果是为它指定了新的内存,就是可以进行修改的;
因此关于String的所有操作函数,实际都不是对字符串本身进行的修改,其最终返回的值都是一个新的引用;
这是字符串的替换函数的源码,可以看到:
字符串的修改
上面说到,String类是不能修改的,所有的修改都会创建新对象,因此这种修改的效率是较低的;
public static void main(String[] args) {
String str1="hello";
String str2="world";
String str=str1+str2;
System.out.println(str);
}
这是上面这段代码的反汇编代码,可以看到,程序的执行过程是较为复杂的,同时在反汇编代码的第3行new了一个StringBuilder对象,什么是StringBuilder呢?
StringBuilder和StringBuffer
为了避免对字符串进行修改时,发生的效率低下的情况,我们可以在对字符串进行修改时借助 StringBuilder和StringBuffer。
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("hello");
//根据索引设置字符的值
sb1.setCharAt(0, 'H');
System.out.println(sb1); //Hello
}
这2个类提供了许多方法对字符串进行操作,同时这2个类与String最大的区别就在于String是不可修改的,但是这2个类是可以进行修改的;
String和StringBuilder类互相转换
- String变为StringBuilder: 利用StringBuilder的构造方法或append()方法;
public static void main(String[] args) {
String str="hello";
//使用StringBuilder的构造方法
StringBuilder builder=new StringBuilder(str);
//使用其append()方法
StringBuilder builder1=new StringBuilder();
builder1.append(str);
}
- StringBuilder变为String: 调用toString()方法
public static void main(String[] args) {
StringBuilder builder=new StringBuilder();
//调用toString方法
String str=builder.toString();
System.out.println(str);
}
StringBuffer与StringBuilder类似,与String的转换方法也类似;
StringBuilder和StringBuffer、String的区别(!)
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改;
- StringBuffer与StringBuilder大部分功能是相似的;
- StringBuffer属于线程安全操作;而StringBuilder属于线程不安全操作;
over!