java------字符串
Java中字符串理解:
当我们使用String s = “hello”;语句创建字符串的时候,首先会去常量池中查找,如果有,就返回这个常量的地址,如果没有,在常量池中创建并返回。world也是这样的。比如这里的“hello”,一开始是没有的,所以要先创建,然后返回一个地址,比如0x01下一次,如果String s= “hello”;的时候,s指向的也会是这个0x01的地址。
String s = "hello"; //常量池中没有常量"hello"就创建,假设地址值为0x001 String s1 = "hello"; //在常量池中查找到"hello",因此s1也指向地址0x001 System.out.println(s==s1); //地址值相同,所以返回的结果为true System.out.println(s1.equals(s));//值相同,所以返回的结果为true
s += "world"//hello world
s+="world" =>"hello world" 在常量池创建一个0x03
之前的变量s会重新指向这个新的地址0x03,而不是原先的0x01 所以说字符串一旦被创建,值就不可改变 这里的值指的字符串本身的值,而不是地址值
1 2 3 | String s2 = new String( "hello" ); //存放在堆中 System.out.println(s2.equals(s)); //比较值是否相同,返回为true System.out.println(s2==s); //比较两个对象地址值,返回false<br><br> |
2.字符串常量相加与变量相加的区别
- 字符串如果是变量相加,是先开辟空间,然后再拼接
- 字符串如果是常量相加,是先加,然后再去常量池里找,如果找到了就返回,如果找不到就创建
String s1 = "hello"; String s2 = "world"; String s3 = "helloworld"; System.out.println(s3==(s1+s2)); //false System.out.println(s3==("hello"+"world")); //true
s3==(s1+s2)的结果是false,是因为变量相加是先在常量池中开辟空间,然后将拼接后的字符串放入开辟的空间之中,因此地址会改变。
s3==(“hello”+“world”)的结果是true,是因为常量相加,是先拼接,然后在常量池中查找,是否有拼接后的字符串,如果有就返回这个地址值,如果没有才会创建新的空间。因为之前s3已经创建了”helloworld“字符串,所以返回的是s3指向的这个地址。因此地址相同。
String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";
String s4 = s1+s2;
String s5 = "helloworld";
System.out.println(System.identityHashCode(s3)); //第一行
System.out.println(System.identityHashCode(s4)); //第二行
System.out.println(System.identityHashCode(s5)); //第三行
第一行与第三行返回的值相同,说明s5优先指向的地址是s3一开始就创建的地址
3.创建字符串的四种方法
//创建字符串对象的四种方法
//public String():创建一个空白字符串对象,不含有任何内容 String s1 = new String(); System.out.println("s1:" + s1); //public String(char[] chs):根据字符数组的内容,来创建字符串对象 char[] chs = {'a', 'b', 'c'}; String s2 = new String(chs); System.out.println("s2:" + s2); //public String(byte[] bys):根据字节数组的内容,来创建字符串对象 byte[] bys = {97, 98, 99}; String s3 = new String(bys); System.out.println("s3:" + s3); //String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc String s4 = "abc"; System.out.println("s4:" + s4);
//显示结果
a1:abc
s2:abc
s3:abc
s4:abc
4.字符串常用的方法
字符串的方法 解释说明
charAt(): 会根据索引获取对应的字符 s.charAt(i) i表示索引 length(): 会返回字符串的长度 s.length()
substring(start,end) 截取字符串 s.substrng(0,3) a b c
substring(start) s.substrng(1) bcde
replace(需要替换的文字,替换成的东西)
split() 按照特殊字符来进行切割
注意点:
在使用split函数的时候注意一下,遇到了正则表达式的特殊符号要注意下, | , + , * , ^ , $ , / , | , [ , ] , ( , ) , - , . , \等特殊符号
package 字符串;
public class testSplit {
public static void main(String[] args) {
String str="1234@abc";
String[] a = str.split("@");
System.out.println("处理结果: "+a[0]+","+a[1]); //输出的是: 处理结果: a[0]=1234,a[1]=abc
String str2="5678|XYZ";
String[] b = str2.split("\\|"); //注意这里用两个 \\,而不是一个\
System.out.println("处理结果: "+b[0]+","+b[1]); //输出的是: 处理结果: b[0]=5678,b[1]=XYZ
String[] b2 = str2.split("|");
System.out.println("str2:"+str2);//5678|XYZ
System.out.println("处理结果:"+b2[0]+","+b2[1]);//5,6
}
}
String str3 = "000000123456";
String newStr = str3.replaceAll("^0*","");
System.out.println("newStr="+newStr);//newStr=123456
String str4 = "1234567000000";
String newStr2 = str4.replaceAll("0+$", "");
System.out.println("newStr2="+newStr2);//newStr2=1234567
5.StringBuilder与StringBuffer、StringJoin
StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("a").append("b").append("c"); System.out.println(stringBuilder.toString()); stringBuilder.reverse(); System.out.println(stringBuilder.toString()); abc cba
//1.创建对象 StringJoiner sj = new StringJoiner(", ","[","]"); //2.添加元素 sj.add("aaa").add("bbb").add("ccc"); int len = sj.length(); System.out.println(len);//15 //3.打印 System.out.println(sj);//[aaa, bbb, ccc] String str = sj.toString(); System.out.println(str);//[aaa, bbb, ccc]
在 Java 语言中,由于 String 类是final 类型的,所以使用 String 定义的字符串是一个常量,因此它一旦创建,其内容和长度是不可改变的。如果需要对一个字符串进行修改,则只能创建新的字符串。
解决方法:可以使用 StringBuffer 类(也称字符串缓冲区)来操作字符串。
说明:StringBuffer 类和 String 类最大的区别在于它的内容和长度都是可以改变的。StringBuffer 类似一个字符容器,当在其中添加或删除字符时,所操作的都是这个字符容器,因此并不会产生新的 StringBuffer 对象。
1.使用StringBuffer类的构造方法初始化字符串对象 StringBuffer 变量名=new String(字符串); 2.借助String类来创建StringBuffer类对象 String s="abc"; StringBuffer s5=new StringBuffer(s); 如果直接 StringBuffer sb = "abc";会报错
StringBuffer s1=new StringBuffer("abcd1234!?,;"); StringBuffer s2=new StringBuffer("987654321987654"); StringBuffer s3=new StringBuffer("987654321"); System.out.println("↓↓↓StringBuffer类的一些常用方法如下↓↓↓"); System.out.println("-----------------------------------------------------"); System.out.println("字符串s1的长度为:" + s1.length());//返回字符串的实际长度 System.out.println("-----------------------------------------------------"); System.out.println("字符串s1所占容器的大小为:" + s1.capacity());//返回字符串所占容器的总大小 System.out.println("-----------------------------------------------------"); System.out.println("获取字符串s1中第2个位置的字符:" + s1.charAt(2)); System.out.println("-----------------------------------------------------"); System.out.println("子字符串'654'第一次出现在字符串s2中的索引为:" + s2.indexOf("654")); System.out.println("从指定的索引6开始搜索,返回子字符串'654'第一次出现在字符串s2中的索引:" + s2.indexOf("654",6)); System.out.println("-----------------------------------------------------"); System.out.println("子字符串'987'最后一次出现在字符串s2中的索引为:" + s2.lastIndexOf("987")); System.out.println("从指定的索引5开始反向搜索,返回字符串'87'在字符串s2中最后一次出现的索引:" + s2.lastIndexOf("87",5)); System.out.println("-----------------------------------------------------"); s1.append('x');//在字符串s1的末尾添加字符'c' s1.append("Java");//在字符串s1的末尾添加字符串"Java" System.out.println("修改后的字符串s1为:" + s1); System.out.println("-----------------------------------------------------"); s1.insert(4,"abcd");//在第4个位置插入字符串"abcd" System.out.println("修改后的字符串s1为:" + s1); System.out.println("-----------------------------------------------------"); s1.deleteCharAt(1);//删除字符串s1中第一个位置的字符 s1.delete(2,5);//删除字符串s1中第2到第4个位置的字符 System.out.println("修改后的字符串s1为:" + s1); System.out.println("-----------------------------------------------------"); s1.replace(4,8,"5678");//将字符串s1中第4到第7个位置的字符串修改为"5678" System.out.println("修改后的字符串s1为:" + s1); System.out.println("-----------------------------------------------------"); s1.setCharAt(1,'b');//将字符串s1中第一个位置的字符修改为'b' System.out.println("修改后的字符串s1为:" + s1); System.out.println("-----------------------------------------------------"); s2.reverse();//将字符串s2反转 System.out.println("修改后的字符串s2为:" + s2); System.out.println("-----------------------------------------------------"); System.out.println("截取字符串s1从第4个位置开始到结尾:" + s1.substring(4)); System.out.println("-----------------------------------------------------"); System.out.println("截取字符串s1从第4个位置开始到第7个位置结尾:" + s1.substring(4,8)); System.out.println("-----------------------------------------------------"); System.out.println("获取s1的变量类型:" + s1.getClass().getName()); System.out.println("将对象信息转化为字符串:" + s2.toString());
↓↓↓StringBuffer类的一些常用方法如下↓↓↓ ----------------------------------------------------- 字符串s1的长度为:12 ----------------------------------------------------- 字符串s1所占容器的大小为:28 ----------------------------------------------------- 获取字符串s1中第2个位置的字符:c ----------------------------------------------------- 子字符串'654'第一次出现在字符串s2中的索引为:3 从指定的索引6开始搜索,返回子字符串'654'第一次出现在字符串s2中的索引:12 ----------------------------------------------------- 子字符串'987'最后一次出现在字符串s2中的索引为:9 从指定的索引5开始反向搜索,返回字符串'87'在字符串s2中最后一次出现的索引:1 ----------------------------------------------------- 修改后的字符串s1为:abcd1234!?,;xJava ----------------------------------------------------- 修改后的字符串s1为:abcdabcd1234!?,;xJava ----------------------------------------------------- 修改后的字符串s1为:accd1234!?,;xJava ----------------------------------------------------- 修改后的字符串s1为:accd5678!?,;xJava ----------------------------------------------------- 修改后的字符串s1为:abcd5678!?,;xJava ----------------------------------------------------- 修改后的字符串s2为:456789123456789 ----------------------------------------------------- 截取字符串s1从第4个位置开始到结尾:5678!?,;xJava ----------------------------------------------------- 截取字符串s1从第4个位置开始到第7个位置结尾:5678 ----------------------------------------------------- 获取s1的变量类型:java.lang.StringBuffer 将对象信息转化为字符串:456789123456789
===============================================================================================================================================================================================================================================================================================================
========================================================================================================================================================
String面试题
1.String是基本类型吗?
String不是基本类型,是引用类型。基本类型只有八种:int,long,float,double,boolean,char,byte,short,每一种对应着相应的包装器。
String是不可变类
2.创建String对象的方式有哪些?区别是什么?
使用new关键字创建:
1) 如果字符串池中没有该字符串常量池,那么就分别在字符串常量池和堆中创建对象,并将堆中的对象的地址返回
2)如果字符串常量池中有该字符,那么就仅在堆中创建对象,并将堆中的对象地址返回
使用双引号创建:
1)此时会在字符串常量池中寻找是否有相应字符串,如果有则返回该地址
2)如果没有则在字符串常量池中创建对象返回地址
3.String, StringBuffer,StringBuilder的区别?
由于String是不可变类,所以是线程安全的,但是由于不可修改,所以每次修改都需要创建新的对象,比较浪费资源,所以引入StringBuffer,StringBuilder类,这两个类都是可变的
StringBuffer和StringBuilder类都是可变类,但是StringBuffer是线程安全的,而StringBuilder是线程不安全的。所以在多线程的环境下可以使用StringBuffer,但是效率和速度没有StringBuilder高
StringBuffer实现线程安全的方法是在内部方法上用synchronized关键字修饰,其实就是加锁。
4.String是不可变的有什么好处?
因为不可变,所以是线程安全的,可以多线程使用
由于不可变,所以可以用于密码存储
可以很好的作为hashmap中key值存储等
5.如何判断两个String是否相等?
(==和equals的区别)==判断的是字符串的地址
equals方法是Object中的方法,在重写之前也是判断地址,但是重写之后就是判断内容是否相等了
所以判断的时候一定要明白对比字符串的地址是从字符串常量池中拿的还是从堆中取的
==和equals的区别
String s1 = "aaa";
String s2 = "aaa";
System.out.println(s1 == s2);//true
System.out.println(s1.equals(s2));//true
String s3 = "bbb";
String s4 = new String("bbb");
System.out.println(s3 == s4);//false
System.out.println(s3.equals(s4));//true
String s5 = s4;
System.out.println(s5 == s4);//true
System.out.println(s5.equals(s4));//true
6.为什么我们在使用HashMap的时候总是用String做key?
因为String是不可变的,这就保证了安全性。
另一方面String很好的重写了Hashcode方法和equals方法
7.String的intern()方法?
当intern()方法被调用,如果字符串池中含有一个字符串和当前调用方法的字符串eqauls相等,那么就会返回池中的字符串。如果池中没有的话,则首先将当前字符串加入到池中,然后返回引用
解释:
1)首先要明白这个方法的返回值是一个字符串,并且保证这个字符串来自于字符串池中
2)当调用方法的对象是堆中的对象时,那么就会将这个堆中的对象加到池中,返回池中的对象地址!
所以其实只要明白了每次创建对象的地址是来自于堆还是字符串池,这些就很好理解
8.字符串相加的原理?
String str1 = "a";
String str2 = "b";
String str3 = "ab";
String str4 = str1 + str2;
String str5 = "a" + "b";
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
问题:为什么str3和str4的地址不同?按理来说都是在字符串池中的对象
String str5 = “a” + “b”; 当字符串相加的部分中全部都是常量时,那么就会直接进入字符串池中进行操作,所以我们生成的str5对象地址就在字符串池中
String str4 = str1 + str2;当字符串相加部分中有变量,那么就会用StringBulider的方式来添加,那么返回的地址就是堆中的地址!
一个在堆中,一个在字符串池中,当然会是false
9.写一个方法来判断一个String是否是回文(顺读和倒读都一样的词)?
如果是用Stringbuild或StringBuffer,可以用resver方法反转字符串,然后调用equals方法判断是否相同
如果不让使用任何API,就直接进行首尾遍历字符串即可
10.如何让一个字符串变成小写或大写形式?
使用toUpperCase 和 toLowerCase 方法让一个字符串变为 大写或小写。
11.如何比较两个字符串?
String内部实现了Comparable接口,有两个比较方法:compareTo(String anotherString) 和compareToIgnoreCase(String str)。
compareTo(String anotherString)
与传入的anotherString字符串进行比较,如果小于传入的字符串返回负数,如果大于则返回证书。当两个字符串值相等时,返回0.此时eqauls方法会返回true。
equalsIgnoreCase(String str)
该方法与compareTo方法类似,区别只是内部利用了Character.toUpperCase等方法进行了大小写转换后进行比较。
12.如何将String转换为char,反过来呢?
String不可能转化为char,但是可以转化为char数组
调用toCharArray() 方法
String str = "hello world";
char[] chars = str.toCharArray();
System.out.println(chars.length);
13.如何将String转换为byte array,反过来呢?
使用String的getBytes()方法将String转成byte数组,使用String的构造方法 new String(byte[] arr) 将byte数据转为String。
14.给几行代码,判断字符串输出是fasle还是true?
其实这个就是自己判断一下对象的地址来自于内存还是字符串池,只有深入理解了,就可以懂了!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?