String类

在这里插入图片描述

1. String


1.1 字符串的不可变性

String是一种不可变对象,字符串中的内容是不可改变的。那么在java中为什么说String字符串具有不可变性?
在这里插入图片描述

观察String类的设计,我们发现String类中有一个value字符数组,这个数组是String类中的字符实际保存的位置。仔细观察,我们能看到这个value数组被final和private修饰着。

final byte[] value = {'H','e','l','l','o'};
//被final修饰的值是一个常量,也就是说我们不能更改value数组中存放的引用
value = new byte[10];//Error
//当我们想要更改value数组中的引用时,编译器会直接报错

//-------------------------------------
//被final修饰说明这个引用不能更改,但是我们却可以通过这个引用去更改原数组的内容
value[0] = 'A';//被final修饰的数组,通过引用去修改数组内容

我们发现被final修饰的byte[] value不是字符串不可变性的原因,这种说法确切的说是错误的,我们修改引用对象中的内容。那么String字符串具有不可变性的原因是什么呢?

  1. 也就是说String类的不可变性的原因之一其实是实际存放字符串的字符数组被private修饰,这就使得这个数组只能在当前类中使用,而在外界获得不到
  2. Java内部在实现String类的过程中将所有涉及到可能修改字符串内容的操作,都采取创建一个新对象,我们所有的改变都是针对新对象而言,而不改变原对象。

1.2 字符常量池

Java中规定,""双引号括起来的字符串,我们称之为字符串常量都是直接存储在堆中的字符串常量池的。那么为什么会有字符串常量池呢?

字符串作为最基础的数据类型,在大量实例化对象的时候会极其耗费时间和空间,JVM为了提高性能,减少资源的耗费会在实力会字符串常量的时候做一些优化,例如:(1)开辟一个字符串常量池String Table;
(2) 创建字符串常量前,先去字符串常量池中检查该字符串是否存在
(3)存在则返回字符串常量池中该字符串的引用;不存在则实例该字符串放入字符串常量池中,并返回该引用。

//我们从下面的代码进行引入,理解字符串常量池
String s1 = "HELLO";//(1)
String s2 = "WORLD";//(2)  
String s3 = "HELLO";//(3)  
String s4 = new String("HELLO");//(4)  
System.out.println("s1的引用是否等于s2的引用:" + (s1 == s2));  
System.out.println("s1的引用是否等于s3的引用:" + (s1 == s3));  
System.out.println("s1的引用是否等于s4的引用:" + (s1 == s4));

程序的执行结果如下:
在这里插入图片描述

我们可以发现s1 == s3,s1 != s4;这是为什么呢?

  1. s1 == s3这也正说明当我们创建字符串常量前,我们会去看字符串常量池中的值,在执行(1)步时我们会先在字符串常量池中寻找"HELLO",当我们发现字符串常量池中没有的时候,我们会在字符串常量池中创建一个并返回当前引用,所以(3)得到的引用与(1)中获得的引用相同。
  2. s1 != s4 其实是在堆中创建一个新的String对象,这个String对象会与字符串常量中的String对象引用同一个字符数组,但是属于不同的对象

也就是说在代码执行前4步时,我们可以理解堆栈图中的关系是这样的:
在这里插入图片描述

1.2.1 intern()

intern()方法是一个native方法,底层由C++实现,看不到具体实现代码,该方法的作用是手动将创建的String对象添加到常量池中

byte [] b = new byte[] {'a','b','c'};
String s1 = new String(b);//(1)
//s1.intern();
String s2 = "abc";//(2)
System.out.println("s1的引用是否等于s2的引用:" + (s1 == s2));

运行程序结果如下:
在这里插入图片描述

将注释段落打开,观察运行结果如下:
在这里插入图片描述

  1. 当我们用字符数组为参数创建一个String对象引用时,此时String对象并不在常量池中。也就是说在执行(1)时,我们并没有在字符串常量池中创建一个String对象,所以在注释//s1.intern()时我们s1所引用对象并不在字符串常量池中,当执行(2)时,我们会在常量池中创建一个String对象,"abc"在常量池中便存在了,这时候我们发现s1 != s2;
  2. 当我们放开s1.intern();之后,我们会将s1对象的引用放入常量池中,这时候我们可以得到s1 == s2;
  • 总结:
    1. 当我们调用intern()方法时,如果字符串常量池中已经包含当前字符串,则返回字符串常量池中的字符串。
    1. 如果字符串常量池中没有这样一个字符串,则会将intern返回的引用指向当前字符串 s1,也就说会返回堆中·字符串常量池中的字符串。

1.3 String类中的常用方法

1.3.1 字符串的构造

//常用的构造方式:
//(1)使用常量串构造
String s1 = "HELLO WORLD";
System.out.println(s1);

//(2)new String 对象
String s2 = new("HELLO WORLD");
System.out.println(s2);

//(3)使用字符数组构造
byte[] array = {'H','E','L','L','O','','W','O','R','L','D'};
String s3 = new String(array);
System.out.println(s3);

1.3.2 其他常见方法

方法功能
boolean equals(Object anObject)判断两个字符串是否相等
int compareTo(String s)比较两个字符串,相等则返回0,调用者大返回> 0的值,调用者小返回< 0的值
int compareToIgnoreCase(String str)与compareTo()方法的功能相同,但是忽略大小写的比较
char charAt(int index)返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常
int indexOf(int ch)返回ch第一次出现的位置,没有返回-1
int indexOf(int ch, int
fromIndex)
从fromIndex位置开始找ch第一次出现的位置,没有返回-1
int indexOf(String str)返回str第一次出现的位置,没有返回-1
int indexOf(String str, int
fromIndex)
从fromIndex位置开始找str第一次出现的位置,没有返回-1
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
char[] toCharArray()将字符串转换成数组
String toLowerCase()字符串转小写
String toUpperCase()字符串转大写
String replaceAll(String regex, String replacement)替换所有的指定内容
String replaceFirst(String regex, String replacement)替换首个出现内容
String[] split(String regex)将字符串以指定格式全部拆分
String[] split(String regex, int limit)将字符串以制定格式拆分,拆分为limit组
String substring(int beginIndex)从指定索引截取到结尾
String substring(int beginIndex, int endIndex)截取部分内容
String trim()去除字符串两边空格,保留中间的空格
public static void main(String[] args) {
	//判断两个字符串是否相等
	String s1 = "hello";
	String s2 = "world";
	System.out.println(s1.equals(s2));//false

	//比较两个字符串
	String s3 = "abc";
	String s4 = "abc";
	String s5 = "abcd";
	String s6 = "ab";
	System.out.println(s3.compareTo(s4));// 0
	System.out.println(s3.compareTo(s5));// <0
	System.out.println(s3.compareTo(s6));// >0

	//比较两个字符串(忽略大小写)
	String s7 = "Abc";
	System.out.println(s3.compareTo(s7));// 0

	//字符串查找
	String s8 = "abcdefghijklmnoocpqrst";  
	System.out.println(s8.charAt(3));// 'd'  
	System.out.println(s8.indexOf('c'));// 2  
	System.out.println(s8.indexOf('c', 10));// 16  
	System.out.println(s8.indexOf("oocp"));// 14  
	System.out.println(s8.indexOf("op", 10));// -1  
	System.out.println(s8.lastIndexOf('c'));// 16  
	System.out.println(s8.lastIndexOf('c', 10));// 2  
	System.out.println(s8.lastIndexOf("pqr"));// 17  
	System.out.println(s8.lastIndexOf("pqr", 19));// 17

	//字符串转数组
	String s9 = "hello";
	char[] ch = s9.toCharArray();
	for(int i = 0;i < ch.length;i++) {
		System.out.println(ch[i]);
	}
	System.out.println();

	//字符串转大写,字符串转小写
	String s10 = "hello";
	String s11 = "HELLO";
	System.out.println(s10.toUpperCase());//HELLO
	System.out.println(s11.toLowerCase());//hello

	//字符串替换
	String s12 = "helloworld" ;  
	System.out.println(s12.replaceAll("l", "_"));//he__owor_d  
	System.out.println(s12.replaceFirst("l", "_"));//he_loworld
	
	//将字符串以指定格式全部拆分
	String s13 = "hello world and code";  
	String[] result1 = s13.split(" ");// 按照空格拆分  
	for(String s: result1) {  
	    System.out.println(s);  
	}  
	//hello  
	//world  
	//and  
	//code  

	//将字符串以指定格式部份拆分
	String[] result2 = s13.split(" ",2) ;  
	for(String s: result2) {  
	    System.out.println(s);  
	}  
	//hello  
	//world and code

	//字符串截取
	String s14 = "helloworld" ;  
	System.out.println(s14.substring(5));//world  
	System.out.println(s14.substring(0, 5));//hello

	//去除字符串两边空格
	String s15 = " hello world  " ;  
	System.out.println("[" + s15 + "]");//[ hello world  ]  
	System.out.println("[" + s15.trim() + "]");//[hello world]
}

好了,以上就是关于String类中常见方法的介绍了,根据实际的应用常见调用String类中的方法可以大大提高我们解决问题的效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值