• Java——String类全面解析


    6c35aa64890648a3bde260bfebd67ecc.gif

    目录

    1、字符串构造

     2、String对象的比较

     2.1、==比较是否变量中的值

    2.2、boolean equal(Object anObject)方法,按照字典序(字符大小顺序)比较

    2.3、compareTo方法:

    2.4、compareToIgnoreCase方法:忽略大小写比较

     3、字符串查找

    4、转化 

     4.1、数值和字符串转化

    4.2、大小写转换

    4.3、字符串转数组

    4.4、格式化

    5、常用方法

    5.1、字符串替换

    5.2、字符串拆分

    5.3、字符串截取

    5.4、trim空格字符处理

    5.5、contains是否包含某内容

    6、字符串常量池

    补充: intern方法

    面试题:

    7、字符串的不可变性

    8、StringBuilder和StringBuffffer

    总结StringBuilder与String类的区别

    面试题:

     9、OJ题巩固

    题目一:字符串中的第一个唯一字符

    题目二:字符串最后一个单词的长度

    题目三:检测字符串是否为回文


     

    String类,在Java中属于字符串类型。

    1、字符串构造

    常用的三种构造字符串的方式:

    代码:

    1. public class Test {
    2. public static void main(String[] args) {
    3. //方法一:
    4. String str1="happy";//str是一个引用变量,happy属于字符串常量
    5. System.out.println(str1);
    6. //方法二:
    7. String str2=new String("lyj");
    8. System.out.println(str2);
    9. //方法三
    10. char[] ch={'l','o','n','g'};//字符数组
    11. String str3=new String(ch);
    12. System.out.println(str3);
    13. }
    14. }

    运行结果:

    2358ea1ba17a47ef91fe56fadb96fbc9.png

    补充:

    String是引用类型,内部并不存储字符串本身 

    查看String类,会看到他有两个属性

     1cceb4c232804efba02d0990178277d6.png

     比如我们看例中的happy的内存分布:

    017f0075236f4e41b1f65fb5b47a322a.png


     

     2、String对象的比较

     

     2.1、==比较是否变量中的值

    例:

    1. public class Test {
    2. public static void main(String[] args) {
    3. int a=10;
    4. int b=30;
    5. int c=10;
    6. System.out.println(a==b);
    7. System.out.println(a==c);
    8. }
    9. }

    运行结果如下:

    9342b7a0e520483b924199750c40ebfe.png

            但是这个比较只针对内置类型,对于引用类型,这么比较就是错误的,因为他比较的是值,也就是比较的是引用中的地址,并没有比较其指向的内容


    2.2、boolean equal(Object anObject)方法,按照字典序(字符大小顺序)比较

    String类重写了父类Object中的Equals方法,Object中equals默认是==比较,源码:

    8c6db8b9af38478ca09a43b4c6cfeb1e.png而String重写,源码:

    ff4ef4ae87c14911b6491c72c756932e.png按照以下规则比较:

    例:

    1. public class Test {
    2. public static void main(String[] args) {
    3. String str1="lyj";
    4. String str2="lya";
    5. String str3="lyj";
    6. System.out.println(str1.equals(str2));
    7. System.out.println(str1.equals(str3));
    8. }
    9. }

     运行:

    61c89ce47bfb489ea32dc149ac1f8d95.png


     

    2.3、compareTo方法:

    查看String中compareTo方法源码:

    73b66ca02ac2440cae4aaa9279f60c16.png

     例:

    1. public static void main(String[] args) {
    2. String str1="lyj";
    3. String str2="lya";
    4. String str3="lyj";
    5. int ret1=str1.compareTo(str2);
    6. if(ret1>0) {
    7. System.out.println("str1>str2");
    8. } else if(ret1==0) {
    9. System.out.println("str1=str2");
    10. } else {
    11. System.out.println("str1);
    12. }
    13. int ret2=str1.compareTo(str3);
    14. if(ret2>0) {
    15. System.out.println("str1>str3");
    16. } else if(ret2==0) {
    17. System.out.println("str1=str3");
    18. } else {
    19. System.out.println("str1);
    20. }
    21. }

     运行结果:

    4d604b4bc09b43b39099379c8a0582fc.png


     

    2.4、compareToIgnoreCase方法:忽略大小写比较

    例: 

    1. public static void main(String[] args) {
    2. String str1="lyj";
    3. String str2="LYJ";
    4. System.out.println(str1.equalsIgnoreCase(str2));
    5. }

    运行结果: 

     3f477ba517d84ee7916c3cfd348f1fc8.png


     

     3、字符串查找

    常用的方法总结:

     

    方法功能
    char  charAt(int  index)放回index位置上字符,如果index为负数或者越界,抛出indexOutOfBoundsException异常
    int  indexOf(int  ch)返回ch第一次出现的位置,没有返回-1
    int  intdexOf(int  ch,int  fromIndex)从fromIndex位置开始找ch第一次出现的位置,没有返回-1
    int  indexOf(String str)返回dtr第一次出现的位置,没有返回-1
    int  indexOf(String  str,int  fromIndex)从fromIndex位置开始找str第一次出现的位置,没有返回-1
    int  lastIndexOf(int  ch)从后往前找,返回ch第一次出现的位置,没有返回-1
    int  lastIndexOf(int  ch,int从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1
    int lastIndexOf(String str)
    从后往前找,返回str第一次出现的位置,没有返回-1
    int lastIndexOf(String str, int
    fromIndex)
    从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返
    回-1

    范例:

    1. public static void main(String[] args) {
    2. String str="abcdcf";
    3. for (int i = 0; i < str.length(); i++) {
    4. char ch=str.charAt(i);
    5. System.out.print(ch+" ");//a b c d e f
    6. }
    7. System.out.println();
    8. System.out.println(str.indexOf('d'));//3
    9. System.out.println(str.indexOf('c',3));//4
    10. String str1="abclyjdcef";
    11. System.out.println(str1.indexOf("lyj"));//3
    12. System.out.println(str1.indexOf("lyj",4));//-1
    13. System.out.println(str1.lastIndexOf('c'));//7
    14. System.out.println(str1.lastIndexOf('c',4));//2
    15. System.out.println(str1.lastIndexOf("lyj"));//3
    16. System.out.println(str1.lastIndexOf("lyj",6));//3
    17. }

     

    4、转化 

     4.1、数值和字符串转化

    1. public static void main(String[] args) {
    2. //其他类型转换为字符串
    3. String str1=String.valueOf(410);
    4. String str2=String.valueOf('l');
    5. String str3=String.valueOf(3.14);
    6. String str4=String.valueOf(3.5f);
    7. String str5=String.valueOf(false);
    8. String str6=String.valueOf(new Person("jingjing",18));
    9. System.out.println(str1+" "+str2+" "+str3+" "+str4+" "+str5+" "+str6);//410 l 3.14 3.5 false Person{name='jingjing', age=18}
    10. //字符串转换为其他类型
    11. int val=Integer.valueOf("410");
    12. int val1=Integer.parseInt("318");
    13. double val2=Double.parseDouble("3.14");
    14. float val3=Float.parseFloat("3.5f");
    15. System.out.println(val+" "+val1+" "+val2+" "+val3);//410 318 3.14 3.5
    16. }

     

    4.2、大小写转换

    1. public static void main(String[] args) {
    2. String str1="family";
    3. System.out.println(str1.toUpperCase());//FAMILY
    4. String str2="LOVE";
    5. System.out.println(str2.toLowerCase());//love
    6. }

     

    4.3、字符串转数组

    1. public static void main(String[] args) {
    2. //字符串转数组
    3. String str1="today is so...";
    4. char[] chars=str1.toCharArray();
    5. for (int i = 0; i < str1.length(); i++) {
    6. System.out.print(chars[i]+" ");//t o d a y i s s o . . .
    7. }
    8. //数组转字符串
    9. String str2=new String(chars);
    10. System.out.println(str2);//today is so...
    11. }

     

    4.4、格式化

    1. public static void main(String[] args) {
    2. String s = String.format("%d-%d-%d", 2022, 8,12);
    3. //有点类似于printf
    4. System.out.println(s);//2022-8-12
    5. }

     

    5、常用方法

    5.1、字符串替换

    方法功能
    String replace(char oldChar,char newChar)替换指定字符
    String replace(String target,String replacement)替换指定内容
    String replaceAll(String regex, String replacement)
    替换所有的指定内容
    String replaceFirst(String regex, String replacement)
    替换收个内容

     范例:

    1. public static void main(String[] args) {
    2. String str1="ablyjlyjablyjabcdef";
    3. String ret=str1.replace('l','k');
    4. System.out.println(ret);//abkyjkyjabkyjabcdef
    5. ret=str1.replace("lyj","cyk");
    6. System.out.println(ret);//abcykcykabcykabcdef
    7. ret=ret.replaceFirst("cyk","lyj");
    8. System.out.println(ret);//ablyjcykabcykabcdef
    9. ret=ret.replaceAll("cyk","lyj");
    10. System.out.println(ret);//ablyjlyjablyjabcdef
    11. }

     

    5.2、字符串拆分

    方法功能
    String[] split(String regex)
    将字符串全部拆分
    String[] split(String regex, int limit)
    将字符串以指定的格式,拆分为limit组
    1. public static void main(String[] args) {
    2. String str="lyjhhh@ccykee";
    3. String[] ret=str.split("@");
    4. System.out.println(Arrays.toString(ret));//[lyjhhh, ccykee]
    5. str="lyj@cyk&lyz@lxm";
    6. ret=str.split("@",2);
    7. System.out.println(Arrays.toString(ret));//[lyj, cyk@lyz@lxm]
    8. }

    注:如果一个字符串中有多个分隔符,可以用"|"作为连字符.

    1. public static void main(String[] args) {
    2. String str="lyz&cyk*lyj@lxm";
    3. String[] ret=str.split("&|@");
    4. System.out.println(Arrays.toString(ret));//[lyz, cyk*lyj, lxm]
    5. }

     

    5.3、字符串截取

    方法功能
    String substring(int beginIndex)从指定索引截取到结尾
    String substring(int beginIndex, int endIndex)截取部分内容

    范例:

    1. public static void main(String[] args) {
    2. String str="helloworld";
    3. String ret1=str.substring(1);
    4. System.out.println(ret1);//elloworld
    5. String ret2=str.substring(1,5);//前开后闭
    6. System.out.println(ret2);//ello
    7. }

     

    5.4、trim空格字符处理

    String trim()  功能:
     
    去掉字符串中的左右空格,保留中间空格

    范例:

    1. public static void main(String[] args) {
    2. String str=" hello world ";
    3. String ret=str.trim();
    4. System.out.println(ret);//hello world
    5. }

     

    5.5、contains是否包含某内容

    判断是否包含某字符串

    1. public static void main(String[] args) {
    2. String str="hellolyjhahaha";
    3. System.out.println(str.contains("lyj"));//true
    4. }

     

    6、字符串常量池

    字符串常量池,其底层是一个StringTable的哈希表

            通俗的来说,就是为了使程序运行得更快,更加节省内存,Java就引出了,池的概念,而字符串常量池,就是存放一些我们常用的字符串,其由双引号括起来的,例:

    String  str  =" lyj ";

    其内存布局:

    3f02775ead624f76bfa055573c533bc0.png

     

    注:上述提到过的,String类有两个属性,一个value,一个hash 

            在字符串常量池中,没有对应的字符串时,将其存入,如果有了,则就会使用那一份现有的数据。

    根据上述提示,分析下面的代码运行结果:

    1. public static void main(String[] args) {
    2. String str1="lyj";
    3. String str2="lyj";
    4. String str3=new String("lyj");
    5. String str4=new String("lyj");
    6. System.out.println(str1==str2);//true
    7. System.out.println(str3==str4);//false
    8. System.out.println(str1==str3);//false
    9. }

    内存布局分析:

    4561b16a1b344607b2d0c420f4a81e67.png

     


    补充: intern方法

     
    该方法的作用是手 动将创建的 String 对象添加到常量池中

     

    1. public static void main(String[] args) {
    2. char[] ch=new char[]{'l','y','j'};
    3. String s1=new String(ch);//没有入池
    4. s1.intern();//入池
    5. String s2="lyj";
    6. System.out.println(s1==s2);//true
    7. char[] ch1=new char[]{'a','b','c'};
    8. String s3=new String(ch1);
    9. String s4="abc";
    10. System.out.println(s3==s4);//false
    11. }

    面试题:

     
    请解释String类中两种对象实例化的区别(常量池中都不存在以下字符串)
     
    JDK1.8中
     
    提示:根据上述例中的内存图,可知,每创建一个字符串对象时,有一个value和一个hash,
     
    value 又指 向对应的字符串,一共两个对象
     
    1. String str = "hello"
     
    正解:2
     
    只会开辟一块堆内存空间,保存在字符串常量池中,然后str共享常量池中的String对象
     
    2. String str = new String("hello")
     
    正解:3
     
    会开辟两块堆内存空间,字符串"hello"保存在字符串常量池中,然后用常量池中的String对象
     
    给新开辟 的String对象赋值。
     
    3. String str = new String(new char[]{'h', 'e', 'l', 'l', 'o'})
     
    正解:3
     
    现在堆上创建一个String对象,然后利用copyof将重新开辟数组空间,将参数字符串数组中内
     
    容拷贝到 String对象中

     

    7、字符串的不可变性

    String类不可变的原因:

    1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
    2. 不可变对象是线程安全的.
    3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中.

    从哪儿观察到不可变呢?观察其源码:

    3e4e09bf0aaf493fb5856a0df37d31c5.png

    而我们在上述的方法中,提到的所有关于会改变字符串的方法,他其实都是新创建了一个对象 

    看以下代码 :

    1. public static void main(String[] args) {
    2. String str="*";
    3. for (int i = 0; i < 20; i++) {
    4. str+=i;
    5. }
    6. System.out.println(str);//*012345678910111213141516171819
    7. }

    我们去查看一下他的汇编:

    afe4e167bf994502b4fe3f40ba4604ca.png

     由于效率太低,因此,引入另一种方法:

    代码改进:

    1. public static void main(String[] args) {
    2. String str="*";
    3. StringBuilder stringBuffer=new StringBuilder();
    4. stringBuffer.append(str);
    5. for (int i = 0; i < 20; i++) {
    6. stringBuffer.append(i);
    7. }
    8. System.out.println(stringBuffer);//*012345678910111213141516171819
    9. }

     不太明白吧?继续向下看咯:


     

    8、StringBuilder和StringBuffffer

    StringBuilder StringBuffffer也可以表示字符串,但他们不能直接赋值
     

    使用举例:

    1. public static void main(String[] args) {
    2. StringBuilder stringBuilder=new StringBuilder("love");
    3. System.out.println(stringBuilder);//love
    4. stringBuilder.reverse();
    5. System.out.println(stringBuilder);//evol
    6. }

     这个字符串逆序,String类是没有这个方法的

            从这可以观察到,StringBuilder和StringBuffffer 与String类的区别,String对字符串内容变动时,都是需要新创建一个对象,并需要接收这个对象,而StringBuilderStringBuffffer它们是对相应的字符串本身进行修改的,因此不需要接收。

    总结StringBuilder与String类的区别

    String:
    1.String创建的对象是不可变的,一旦创建不可改变
    2.对象值可以改变其实是创建了一个新的对象,然后把新的值保存进去
    3.String类被final修饰,不可以被继承
    4.String创建的对象的值存在于常量池,不用的时候不会被销毁
    5.String运行时间较长
    6.String适用于比较短而小的字符串


    StringBuffer

    1.StringBuffer创建的对象是可变的
    2.它的改变不像String那样重新创建对象,而是通过构造方法
    3.StringBuffer创建的对象的值存在于栈区,不用的时候会被销毁
    4.StringBuffer运行时间较短
    5.StringBuffer适用于比较长的字符串、比较多的字符串

    StringBuilder具体其他的方法,可以查看文档:http:// StringBuilder在线文档

    补充:1、String与StringBuilder相互转换:

     
    1. public static void main(String[] args) {
    2. String str="love";
    3. StringBuilder stringBuilder=new StringBuilder(str);//String变成了StringBuilder
    4. System.out.println(stringBuilder);
    5. }
    1. StringBuilder s = new StringBuilder("nice");
    2. String s = s.toString();

     

    面试题:

     

     

    1. String、StringBuffffer、StringBuilder的区别?
     
    String的内容不可修改,StringBuffffer与StringBuilder的内容可以修改.
     
    StringBuffffer与StringBuilder大部分功能是相似的
     
    StringBuffffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程
     
    不安全操
     
    2. 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】
     

     

    String str = new String("ab"); // 会创建 2个对象
     
    String str = new String("a") + new String("b"); // 会创建 6个对象

    第二题的不理解看图: 

    a0b0c23690b449259e77b457ab4ab9e2.png

    toString转换会new新的对象:

    ff85e2d757a842c48d44de28c94e8678.png


     

     9、OJ题巩固

    题目一:字符串中的第一个唯一字符

     题目描述:

    e087cd2d5c254f3a844657fb2cd5c868.png

    两次遍历

    count为计数数组(利用ASCII码,a对应97),一开始创建的count数组,里面所有值默认为0

    第一次遍历, 用字符的ASCII码减去'a',得到的下标就与计数数组对应上了,将其加一

    第二次遍历,将第一个为1的返回即可

    代码: 

    1. class Solution {
    2. public int firstUniqChar(String s) {
    3. int[] count=new int[26];
    4. for(int i=0;i
    5. char ch=s.charAt(i);
    6. count[ch-'a']++;
    7. }
    8. for(int i = 0;i
    9. char ch=s.charAt(i);
    10. if(count[ch-'a']==1) {
    11. return i;
    12. }
    13. }
    14. return -1;
    15. }
    16. }

    测试通过:

    7dabeab868054ede94d65dbfb3576902.png

     

     

    题目二:字符串最后一个单词的长度

     解法一:找到最后一个空格的位置,用总长度减去即可

    代码:

    1. import java.io.InputStream;
    2. import java.util.Scanner;
    3. public class Main{
    4. public static void main(String [] args) throws Exception{
    5. Scanner sc=new Scanner(System.in);
    6. String str= sc.nextLine();
    7. int n=str.lastIndexOf(' ');
    8. int x=str.length();
    9. System.out.println(x-n-1);
    10. }
    11. }

    测试通过:

    27d2f665bda24a64855004a383548c46.png

     解法二:用字符串分割方法,输出其数组的最后一个字符串的长度

     代码:

    1. import java.io.InputStream;
    2. import java.util.Scanner;
    3. public class Main{
    4. public static void main(String [] args) throws Exception{
    5. Scanner sc=new Scanner(System.in);
    6. String str= sc.nextLine();
    7. String[] ret=str.split(" ");
    8. System.out.println(ret[ret.length-1].length());
    9. }
    10. }

    测试通过:

    7fcbaed20d0549159569f80c5c06831a.png

     

    题目三:检测字符串是否为回文

    题目描述:

    e62b9470c4bb43c69b33642d673389d4.png

     思路在代码中有注释:

    代码: 

    1. class Solution {
    2. //有效字符判断
    3. public boolean isEffective(char ch) {
    4. return Character.isLetterOrDigit(ch);
    5. }
    6. public boolean isPalindrome(String s) {
    7. //统一大小写
    8. s=s.toLowerCase();
    9. int right=s.length()-1;
    10. int left=0;
    11. //回文判断
    12. while(left
    13. while(leftisEffective(s.charAt(left))) {
    14. left++;
    15. }
    16. while(leftisEffective(s.charAt(right))) {
    17. right--;
    18. }
    19. if(s.charAt(left)!=s.charAt(right)) {
    20. return false;
    21. }
    22. left++;
    23. right--;
    24. }
    25. return true;
    26. }
    27. }

    测试通过:

    6e5be025aaba4768be43862eb63fba59.png

     

     

    f0ae59df688b4713bc62ac73d29924c9.gif

     

  • 相关阅读:
    Python编辑器和Pycharm的傻瓜式安装部署
    vue2 解密图片地址(url)-使用blob文件-打开png格式图片
    您需要了解的有关NFT的所有知识
    在单链表中删除所有值为x的结点
    vue3.0的变化汇总
    (二)Ubuntu系统Pytorch环境配置
    SQL:sql连接那些事儿
    Ensembling Off-the-shelf Models for GAN Training(GAN模型迎来预训练时代,仅需1%的训练样本)
    Python3《机器学习实战》学习笔记(四):朴素贝叶斯实战篇之新浪新闻分类
    MySql学习笔记11——DBA命令介绍
  • 原文地址:https://blog.csdn.net/LYJbao/article/details/126283199