Java——String类全面解析

Java (51) 2023-10-17 21:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说Java——String类全面解析,希望能够帮助你!!!。

目录

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

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

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

4.1、数值和字符串转化

5.5、contains是否包含某内容

8、StringBuilder和StringBuffffer

总结StringBuilder与String类的区别

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

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

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

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

1、字符串构造

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

代码:

public class Test {
    public static void main(String[] args) {
        //方法一:
        String str1="happy";//str是一个引用变量,happy属于字符串常量
        System.out.println(str1);

        //方法二:
        String str2=new String("lyj");
        System.out.println(str2);

        //方法三
        char[] ch={'l','o','n','g'};//字符数组
        String str3=new String(ch);
        System.out.println(str3);
    }
}

运行结果:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第1张

补充:

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

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

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第2张

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

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第3张

2、String对象的比较

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

例:

public class Test {
    public static void main(String[] args) {
        int a=10;
        int b=30;
        int c=10;
        System.out.println(a==b);
        System.out.println(a==c);
    }
}

运行结果如下:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第4张

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

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

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

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第5张

而String重写,源码:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第6张

按照以下规则比较:

例:

public class Test {

    public static void main(String[] args) {
        String str1="lyj";
        String str2="lya";
        String str3="lyj";
        System.out.println(str1.equals(str2));
        System.out.println(str1.equals(str3));
    }
}

运行:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第7张

2.3、compareTo方法:

查看String中compareTo方法源码:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第8张

例:

public static void main(String[] args) {
        String str1="lyj";
        String str2="lya";
        String str3="lyj";
        int ret1=str1.compareTo(str2);
        if(ret1>0) {
            System.out.println("str1>str2");
        } else if(ret1==0) {
            System.out.println("str1=str2");
        } else {
            System.out.println("str1<str2");
        }
        int ret2=str1.compareTo(str3);
        if(ret2>0) {
            System.out.println("str1>str3");
        } else if(ret2==0) {
            System.out.println("str1=str3");
        } else {
            System.out.println("str1<str3");
        }
    }

运行结果:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第9张

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

例:

public static void main(String[] args) {
        String str1="lyj";

        String str2="LYJ";
        System.out.println(str1.equalsIgnoreCase(str2));

    }

运行结果:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第10张

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

范例:

public static void main(String[] args) {

        String str="abcdcf";
        for (int i = 0; i < str.length(); i++) {
            char ch=str.charAt(i);
            System.out.print(ch+" ");//a b c d e f
        }
        System.out.println();
        System.out.println(str.indexOf('d'));//3
        System.out.println(str.indexOf('c',3));//4

        String str1="abclyjdcef";
        System.out.println(str1.indexOf("lyj"));//3
        System.out.println(str1.indexOf("lyj",4));//-1

        System.out.println(str1.lastIndexOf('c'));//7
        System.out.println(str1.lastIndexOf('c',4));//2
        System.out.println(str1.lastIndexOf("lyj"));//3
        System.out.println(str1.lastIndexOf("lyj",6));//3

    }

4、转化

4.1、数值和字符串转化

public static void main(String[] args) {

        //其他类型转换为字符串
        String str1=String.valueOf(410);
        String str2=String.valueOf('l');
        String str3=String.valueOf(3.14);
        String str4=String.valueOf(3.5f);
        String str5=String.valueOf(false);
        String str6=String.valueOf(new Person("jingjing",18));
        System.out.println(str1+" "+str2+" "+str3+" "+str4+" "+str5+" "+str6);//410  l  3.14  3.5  false  Person{name='jingjing', age=18}

        //字符串转换为其他类型
        int val=Integer.valueOf("410");
        int val1=Integer.parseInt("318");
        double val2=Double.parseDouble("3.14");
        float val3=Float.parseFloat("3.5f");
        System.out.println(val+" "+val1+" "+val2+" "+val3);//410  318  3.14  3.5

    }

4.2、大小写转换

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

4.3、字符串转数组

public static void main(String[] args) {
        //字符串转数组
        String str1="today is so...";
        char[] chars=str1.toCharArray();
        for (int i = 0; i < str1.length(); i++) {
            System.out.print(chars[i]+" ");//t o d a y   i s   s o . . .
        }

        //数组转字符串
        String str2=new String(chars);
        System.out.println(str2);//today is so...
    }

4.4、格式化

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

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)

替换收个内容

范例:

public static void main(String[] args) {
        String str1="ablyjlyjablyjabcdef";
        String ret=str1.replace('l','k');
        System.out.println(ret);//abkyjkyjabkyjabcdef
        ret=str1.replace("lyj","cyk");
        System.out.println(ret);//abcykcykabcykabcdef
        ret=ret.replaceFirst("cyk","lyj");
        System.out.println(ret);//ablyjcykabcykabcdef
        ret=ret.replaceAll("cyk","lyj");
        System.out.println(ret);//ablyjlyjablyjabcdef
    }

5.2、字符串拆分

方法

功能

String[] split(String regex)

将字符串全部拆分

String[] split(String regex, int limit)

将字符串以指定的格式,拆分为limit组

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

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

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

    }

5.3、字符串截取

方法

功能

String substring(int beginIndex)

从指定索引截取到结尾

String substring(int beginIndex, int endIndex)

截取部分内容

范例:

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

5.4、trim空格字符处理

String trim() 功能:

去掉字符串中的左右空格 , 保留中间空格

范例:

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

5.5、contains是否包含某内容

判断是否包含某字符串

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

6、字符串常量池

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

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

String  str  =" lyj ";

其内存布局:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第11张

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

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

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

public static void main(String[] args) {
        String str1="lyj";
        String str2="lyj";
        String str3=new String("lyj");
        String str4=new String("lyj");

        System.out.println(str1==str2);//true
        System.out.println(str3==str4);//false
        System.out.println(str1==str3);//false
    }

内存布局分析:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第12张

补充: intern方法

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

public static void main(String[] args) {
        char[] ch=new char[]{'l','y','j'};
        String s1=new String(ch);//没有入池
        s1.intern();//入池
        String s2="lyj";
        System.out.println(s1==s2);//true

        char[] ch1=new char[]{'a','b','c'};
        String s3=new String(ch1);
        String s4="abc";
        System.out.println(s3==s4);//false
    }

面试题:

请解释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 中.

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

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第13张

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

看以下代码 :

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

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

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第14张

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

代码改进:

public static void main(String[] args) {
        String str="*";
        StringBuilder stringBuffer=new StringBuilder();
        stringBuffer.append(str);
        for (int i = 0; i < 20; i++) {
            stringBuffer.append(i);
        }
        System.out.println(stringBuffer);//*012345678910111213141516171819
    }

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

8、StringBuilder和StringBuffffer

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

使用举例:

public static void main(String[] args) {
        StringBuilder stringBuilder=new StringBuilder("love");
        System.out.println(stringBuilder);//love

        stringBuilder.reverse();
        System.out.println(stringBuilder);//evol
    }

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

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

总结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相互转换:

public static void main(String[] args) {
        String str="love";
        StringBuilder stringBuilder=new StringBuilder(str);//String变成了StringBuilder
        
        System.out.println(stringBuilder);
    }
StringBuilder s = new StringBuilder("nice");
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个对象

第二题的不理解看图:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第15张

toString转换会new新的对象:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第16张

9、OJ题巩固

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

题目描述:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第17张

两次遍历

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

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

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

代码:

class Solution {
    public int firstUniqChar(String s) {
        int[] count=new int[26];

        for(int i=0;i<s.length();i++) {
            char ch=s.charAt(i);
            count[ch-'a']++;
        }
        for(int i = 0;i<s.length();i++) {
            char ch=s.charAt(i);
            if(count[ch-'a']==1) {
                return i;
            }
        }
        return -1;
    }
}

测试通过:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第18张

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

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

代码:

import java.io.InputStream;
import java.util.Scanner;

public class Main{
     public  static void  main(String [] args) throws Exception{
        Scanner sc=new Scanner(System.in);
        String str= sc.nextLine();
        int n=str.lastIndexOf(' ');
         int x=str.length();
         System.out.println(x-n-1);
     }
}

测试通过:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第19张

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

代码:

import java.io.InputStream;
import java.util.Scanner;

public class Main{
     public  static void  main(String [] args) throws Exception{
        Scanner sc=new Scanner(System.in);
        String str= sc.nextLine();
         String[] ret=str.split(" ");
         System.out.println(ret[ret.length-1].length());
     }
}

测试通过:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第20张

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

题目描述:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第21张

思路在代码中有注释:

代码:

class Solution {
    //有效字符判断
    public boolean isEffective(char ch) {
        
        return Character.isLetterOrDigit(ch);
    }
    public boolean isPalindrome(String s) {
        //统一大小写
        s=s.toLowerCase();

        int right=s.length()-1;
        int left=0;
        //回文判断
        while(left<right) {
            while(left<right&&!isEffective(s.charAt(left))) {
                left++;
            }
            while(left<right&&!isEffective(s.charAt(right))) {
                right--;
            }
            if(s.charAt(left)!=s.charAt(right)) {
                return false;
            } 
            left++;
            right--;
        }
        return true;

    }
}

测试通过:

Java——String类全面解析_https://bianchenghao6.com/blog_Java_第22张

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

发表回复