Java中的String类

1.String类

1.1 特性

  1. String类为final类,不可被继承,代表不可变的字符序列;

  2. 实现了Serializable接口,表示字符串支持序列化; 实现了Comparable接口,表示字符串可比较大小;

  3. String对象的字符内容是存储在内部的final char型数组value中的;该数组不可再赋值,其元素也不能再改变;

  4. 字符串是常量,用双引号表示,具有不可变性,其值在创建之后不能改变;体现:
    1)当对字符串引用重新赋值时,需重新开辟内存区域进行赋值,不能使用原有的value数组进行赋值;
    2)当对现有字符串进行拼接操作时,需重新开辟内存区域进行赋值,不能使用原有的value数组进行赋值;
    3)当使用replace方法对字符串内容进行修改时,需重新开辟内存区域进行赋值,不能使用原有的value数组进行赋值;

  5. 通过字面量的方式(区别于new)给一个字符串引用赋值,该字符串值声明在字符串常量池中;

  6. 字符串常量池不会存储相同内容的字符串;

在这里插入图片描述

1.2 面试题

面试题1: 通过1)字面量方式声明变量;2)new String(“xxx”)的方式声明变量,的区别?

字符串常量存储在方法区的字符串常量池中,目的是共享; 字符串非常量对象存储在堆中;

面试题2: String s=new String(“abc”)方式创建对象,在内存中创建了几个对象?

1)堆空间中的new 结构;2)value数组对应的字符串常量池中的数据"abc";

面试题3final 修饰的字符串变量为常量,存储在常量池!

在这里插入图片描述
在这里插入图片描述

结论:通过不同的字面量赋值方式进行变量声明,有什么区别?

  • 如果只是不同字面量的拼接,则拼接结果在常量池;
  • 一旦拼接对象涉及到变量,则拼接结果在堆中;
  • 如果拼接结果调用intern()入池方法,则方法返回值在常量池中;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3 常用方法

int compareTo(String anotherString):该方法返回值有3中可能:比如"当前串".compareTo(“被比较串”)

  • 0:表示两个字符串内容相等;
  • >0:表示当前串大于被比较串;
  • <0表示当前串小于被比较串;

在这里插入图片描述
indexOf(str)和lastIndexOf(str)的返回值什么情况下相等?

  • case1:原始串中只有一个str;
  • case2:str不存在,返回值均为-1;

在这里插入图片描述
regex是正则表达式,比较复杂:
之前一个坑点就是split时,如果以反斜杠进行分割,在regex中切记使用\\\\四个反斜杠!!
在这里插入图片描述

1.4 String与其他类型之间的转换

1.基本数据类型与String之间的转换

String->基本数据类型:借助基本数据类型对应的包装类中的,包装类.parse类型(字符串)实现,比如Integer.parseInt(“123”); 基本数据类型->String:使用String.valueOf(数据)实现,如String.valueOf(123);

2.字符串数组与String之间的转换
一般Java中涉及到区间,均为左闭右开区间;
在这里插入图片描述
3.Byte数组与String之间的转换
此处需要注意不同的编码集所表现的效果可能不同!!
字节数组->字符串时可指定解码的字符集,使用new String(byte[],String charsetName)
编写程序时需要注意,编码字符集与解码字符集需要保持一致,否则会出现乱码!!
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.northsmile.string;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

/**
 * Author:NorthSmile
 * Date:2023/3/23 19:45
 * 字符串相关例题
 */
public class Example {
    // 模拟trim函数
    public static String trim(String s){
        // 先将s转为字符数组
        char[] chs=s.toCharArray();
        int n=chs.length;
        // 找到左端最后一个非空格的位置
        // 找右端最后一个非空格的位置
        int i=0;
        while (i<n&&chs[i]==' '){
            i++;
        }
        int j=n-1;
        while (j>=i&&chs[j]==' '){
            j--;
        }
        // 将两个位置之间的字符取出来 实例化为字符串
        return new String(chs,i,j+1-i);
    }

    // 对字符串指定范围进行反转
    public static String reverse(String s,int start,int end){  // 左闭右开
        // 先将s转为字符数组
        char[] chs=s.toCharArray();
        int n=chs.length;
        // 使用双指针对指定范围进行反转
        int left=start,right=end-1;
        while (right>left){
            swap(chs,left,right);
            left++;
            right--;
        }
        return new String(chs);
    }

    private static void swap(char[] chs, int left, int right) {
        char temp=chs[left];
        chs[left]=chs[right];
        chs[right]=temp;
    }

    // 获取一个字符串在另一个串中出现的次数
    public static int findStr(String mainStr,String pattern){
        // 暴力搜索
        int i=0;
        int count=0;
        while (i<=mainStr.length()-pattern.length()){
            int index = mainStr.indexOf(pattern, i);
            if (index==-1){
                break;
            }
            count++;
            i=index+1;  // i从当前匹配位置的下一个位置开始搜索;
        }
        return count;
    }

    // 获取两个字符串的最大相同子串(只取最左面的)
    public static String longestCommonStr(String str1,String str2){
        // 确定两者之间的较短者
        if (str1==null||str2==null){
            return null;
        }
        String max=str1.length()>=str2.length()?str1:str2;
        String min=str1.length()<str2.length()?str1:str2;
        int n=min.length();
        // 双指针
        for (int i=0;i<n;i++){  // i表示此时搜索子串长度为n-i
            int start=0;  // 子串起点
            int end=n-i;  // 子串终点+1
            while (end<=n){
                String subString=min.substring(start,end);
                if (max.contains(subString)){
                    return subString;
                }
                start++;
                end++;
            }
        }
        return null;
    }

    // 获取两个字符串的最大相同子串(所有)
    public static Set<String> longestCommonStr2(String str1,String str2){
        // 确定两者之间的较短者
        if (str1==null||str2==null){
            return null;
        }
        String max=str1.length()>=str2.length()?str1:str2;
        String min=str1.length()<str2.length()?str1:str2;
        int n=min.length();
        // 双指针
        for (int i=0;i<n;i++){  // i表示此时搜索子串长度为n-i
            int start=0;  // 子串起点
            int end=n-i;  // 子串终点+1
            Set<String> res=new HashSet<String>();
            while (end<=n){
                String subString=min.substring(start,end);
                if (max.contains(subString)){
                    res.add(subString);
                }
                start++;
                end++;
            }
            if (res.size()!=0){
                return res;
            }
        }
        return null;
    }

    // 对字符串中字符进行自然顺序排序
    // 将s转为字符数组,然后对数组进行排序,再讲排序后的数组转为字符串即可
    public static String sortStr(String s){
        char[] chs = s.toCharArray();
        // 进行排序,这里使用手动编写的优化快排(可以直接调用Arrays.sort(chs)即可)
        quickSort(chs,0,chs.length-1);
        return new String(chs);
    }

    private static void quickSort(char[] chs, int left, int right) {
        if (right-left<=15){
            // 小区间数组使用直接插入排序
            insertionPartition(chs,left,right);
            return;
        }
        // 进行分区
        int pos=partitionByHole(chs,left,right);
        // 处理左右分区
        quickSort(chs,left,pos-1);
        quickSort(chs,pos+1,right);
    }

    // 基于“挖坑法”的分区函数
    private static int partitionByHole(char[] chs, int left, int right) {
        // 通过随机数法确定基准元素
        swap(chs,left,new Random().nextInt(right-left+1)+left);
        char pivot=chs[left];
        // 分区
        int i=left,j=right;
        while (i<j){
            while (i<j&&chs[j]>=pivot){
                j--;
            }
            chs[i]=chs[j];
            while (i<j&&chs[i]<=pivot){
                i++;
            }
            chs[j]=chs[i];
        }
        chs[i]=pivot;
        return i;
    }

    // 指定区间上的直接插入排序
    private static void insertionPartition(char[] chs, int left, int right) {
        for (int i=left+1;i<=right;i++){
            for (int j=i;j>left&&chs[j]<chs[j-1];j--){
                swap(chs,j,j-1);
            }
        }
    }

    public static void main(String[] args) {
//        System.out.println("-"+trim("     ")+"-");
//        System.out.println("-"+trim(" ")+"-");
//        System.out.println("-"+trim("     abc def    ")+"-");

//        System.out.println(reverse("abcdef",0,6));  // fedcba
//        System.out.println(reverse("abcdef",1,6));  // afedcb
//        System.out.println(reverse("abcdef",1,5));  // aedcbf

//        System.out.println(findStr("abkkcadkabkebfkabkskab","ab"));
//        System.out.println(findStr("aaaaaaaa","aa"));

//        System.out.println(longestCommonStr("abcwerthello1yuiodefabcdef","hello1"));
        System.out.println(longestCommonStr("abcwerthello1yuiodefabcdef","hello1abcdef"));
        System.out.println(longestCommonStr2("abcwerthello1yuiodefabcdef","hello1abcdef"));
//        System.out.println(sortStr("abkkcadkabkebfkabkskab"));
    }
}

2. StringBuilder类、StringBuffer类:可变字符序列

String、StringBuilder、StringBuffer三者的相同点与不同点?

不同点:

String:不可变的字符序列;
StringBuffer:可变的字符序列;线程安全,效率低;JDK5.0
StringBuilder:可变的字符序列;线程不安全,效率高;JDK5.0新增的类;

相同点:

均与字符串操作相关,且底层均使用char型数组存储数据;

StringBuilder/StringBuffer内容可变的原因:
使用无参构造StringBuilder()时,会默认开辟长度为16的char型数组value,用于后续进行数据添加;
使用有参构造StringBuilder(String str)时,会开辟长度为str.length()+16的char型数组value,用于后续进行数据添加;
在数据append时,发现此时的value数组不足以存储数据,则需要进行数组扩容操作1)默认将数组容量扩充到原始大小的2倍+2;2)将数组原始内容复制到扩充后的数组中;
已知可变字符序列在内容新增时可能出现数组扩容操作,而扩容操作涉及到数组内容复制,效率较低故我们在使用StringBuilder/StringBuffer时,可以在最开始实例化对象时使用有参构造StringBuilder(int capacity),在最开始就创建一个大小合适的value数组,尽量避免数组扩容带来的负面影响。
在这里插入图片描述

在这里插入图片描述

StringBuilder/StringBuffer常用方法:
二者提供的方法一致,其使用方法统一,区别在于StringBuffer线程安全:
在这里插入图片描述
在这里插入图片描述

三者效率关系:
StringBuilder>StringBuffer>String

资料来源:尚硅谷

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NorthSmile

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值