String类的深度剖析

文章目录

  • 1.String类的基本用法(1)基本构造方法
  •                                       (2)字符串的常见方法
  • 2.字符串常量池
  • 3.字符串的不可变性(1)字符串为什么不可变
  •                                    (2)字符串设计成不可变的原因
  •                                        (3)用String拼接字符串的低效性
  • 4.认识StringBuffer和StringBuilder(1)常用方法
  •                                                          (2)StringBuilder和StringBuffer拼接字符串相比于String拼接
  •                                                         (3)StringBuilder  StringBuffer 和String的区别
  • 5.String类型底层实现

一.String类的基本用法

1.字符串构造的基本方法

主要有三种方法

public static void main(String[] args) {
        String a="hello1";//使用常量串构造
        String b=new String("hello2");//直接newString对象
        char[]arr={'h','e','l','l','o','3'};//使用字符数组进行构造
         String c=new String(arr);
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
    }

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

String s1=new String("hello")

String s2=new String("world")

2.字符串的常见方法:

(1)boolean equals();逐个字符进行比较

 public static void main3(String[] args) {
        String c="hello1";
        String d="iello1";


        System.out.println((c.equals(d)));


    }

 

 public static void main(String[] args) {
        String c="hello1";
        String d="hello1";


        System.out.println((c.equals(d)));

    }

 

(2)int compareTo(String s)

1.先按照次序进行比较,如果出现不相等的字符,返回这两个字符的大小差值

2.如果k个字符相等(k为两个字符长度的最小值),返回值为两个字符串长度的差值

 public static void main(String[] args) {
        String j="gho";
        String k="ih";
        System.out.println(j.compareTo(k));

    }

 按照次序依次进行比较,我们知道'j'比'i'小2,所以最终结果就为-2.

 public static void main(String[] args) {
        String j="ghoabc";
        String k="gho";
        System.out.println(j.compareTo(k));

    }

 字符串j和字符串k前三个字符都相等了,那么最终结果就是字符串长度的差值也就是3.

(3)char charAt(int i)     返回i位置上的字符

public static void main9(String[] args) {
        String k="abcefgdfg";
        //char b=k.charAt(0);
        System.out.println(k.charAt(1));
        System.out.println(k.charAt(3));
    }

 

(4)int  indexOf(int ch)   返回ch第一次出现的位置,没有返回-1.

 public static void main10(String[] args) {
        String k="abcefgdfg";
        System.out.println(k.indexOf('e'));
        System.out.println(k.indexOf('f'));
        System.out.println(k.indexOf('z'));
    }

(5)int indexOf(int ch,int from index)    从fromindex 位置上开始找字符ch,没有则返回-1;

 public static void main(String[] args) {
        String l="rghzbfgcv";
        System.out.println(l.indexOf('c',6));
        System.out.println(l.indexOf('g',2));
    }

 

(6)int indexOf(String str)  返回str第一次出现的位置,没有则返回-1;

  public static void main12(String[] args) {
        String l="rghzbfgcv";
        System.out.println(l.indexOf("ghz"));
        System.out.println(l.indexOf("zbf"));
        System.out.println(l.indexOf("gcf"));
    }

(7)int indexOf(String str,int fromIndex)  从fromIndex位置上开始找字符串str第一次出现的位置,没有找到就返回-1;

public static void main13(String[] args) {
        String l="rghzbfrghzcv";
        System.out.println(l.indexOf("ghz",3));
        System.out.println(l.indexOf("rgh",6));

    }

 

(8) int lastindexOf(int ch)从后往前找,返回ch第一次出现的位置,没有则返回-1

  int lastindexOf(int ch,int a)从a位置开始从后往前找,找到ch第一次出现的位置,没有则返回-1;

int lastindexOf(String str) 从后往前找str第一次出现的位置,没有则返回-1;

int lastindexOf(String str,int a)从a位置从后往前找str第一次出现的位置,没有则返回-1;

(9)数值和字符串的转化

//数字转字符串   String  valueOf();

public static void main111(String[] args) {
        String b=String.valueOf(1234);
        String c=String.valueOf(12.38);
        
        System.out.println(b);
        System.out.println(c);
      

    }

//字符串转数字

public static void main(String[] args) {
        int a=Integer.parseInt("128");
        double b=Double.parseDouble("15.67");
        System.out.println(a);
        System.out.println(b);
    }

 

 字符串大小写的相互转换

 public static void main97(String[] args) {
        String d="abcdefF1";
        String f="vbHELLO4";
        System.out.println(d.toUpperCase());
        System.out.println(f.toLowerCase());


    }

字符串和数组的相互转换

 public static void main98(String[] args) {
        String d="abcdefF1";
        char[]f=d.toCharArray();
        for (int i = 0; i < d.length(); i++) {
            System.out.print(f[i]+" ");

        }
        System.out.println();
        char[]arr={'a','b','c'};
        String l=new String(arr);
        System.out.println(l);


        //System.out.println(Arrays.toString(d));

    }

(10)字符串替换

String replaceAll(String source,String replace);全部替换

String replaceFirst(String source,String replace);部分替换

public static void main55(String[] args) {
        String fh="hellollo";
        System.out.println(fh.replaceAll("llo","www"));
    }

    public static void main(String[] args) {
        String str="helloworld";
        System.out.println(str.replaceAll("l","t"));
        System.out.println(str.replaceFirst("l","w"));

    }

 (11)字符串拆分

String[]split(String regex)以regex为分割符全部拆分

String[]split(String regex,int b)以regex为分割符拆分成两b部分                                                        

public static void main58(String[] args) {
        String a="hello good study";
        String[]arr2=a.split(" ");
        for (String x: arr2) {
            System.out.println(x);

        }

public static void main57(String[] args) {
        String fg="hello&world&haha";
        String[]arr=fg.split("&",2);
        for (String x: arr) {
            System.out.println(x);

        }

 

如果分割符是”|","*","+"都得加上转义字符,前面加"\".

 public static void main59(String[] args) {
        String b="day.day.up";
        String[]arr3=b.split("\\.");
        for (String x: arr3) {
            System.out.println(x);

        }

 如果分割符是"\\",那么就得写成"\\\\"

public static void main60(String[] args) {
        String c="i\\love\\you";
        String[]arr4=c.split("\\\\");
        for (String x: arr4) {
            System.out.println(x);

        }

如果一个字符串中有多个分割符,可以用"1"作为连字符

 public static void main62(String[] args) {
        String f="good,food&day";
        String[]arr6=f.split(",|&");
        for (String x: arr6) {
            System.out.println(x);

        }

 (12)字符串截取

String substring(int beginindex)从指定位置开始往后截取全部

String substring(int beginindex,int endindecx) 根据指定的前后位置截取一部分,注意是左闭右开,[bejinindex,endindex];

 public static void main63(String[] args) {
        String c="gouba";
        System.out.println(c.substring(2));
    }

public static void main(String[] args) {
        String b="helloworld";
        System.out.println(b.substring(2,5));
    }

从下标2位置开始截取,截取到下标为5的位置,但下标为5的位置上的元素并不被截取

(13)String  trim() 去掉字符串开头和结尾的空白字符串(空格、换行,制表符等)

public static void main(String[] args) {
        String c=" hello1 ";
        c=c.trim();
        System.out.println(c);
    }

二.字符串常量池

大家先来一起看一段代码

public static void main1(String[] args) {
        String s1="hello";
        String s2="hello";
        String s3=new String("hello");
        System.out.println(s1==s2);
        System.out.println(s2==s3);
        
       

    }

 大家一起来看一下

当s1所指向的常量字符串在常量池当中没有时,会自动地把它保存在常量池当中去,当s2创建对象hello时会直接拿过来用,使s2指向s1创建的对象 ,s1和s2相等,而对于s3因为它是new了一个hello,所以不管常量池当中有没有hello,它都是唯一的,所以s2!=s3.

只要是new的对象,它就是唯一的。

2.intern()的使用    对于像String s1="hello"这样的常量字符串,当常量池当中没有hello,会自动的把它放到常量池当中去,而像String b=new String("hello")这种形式,当常量池当中没有时,并不会自动的添加到常量池当中去,需要我们用intern函数手动添加到常量池当中去。

 public static void main(String[] args) {
        String c=new String("hello");
       // c=c.intern();
        String d="hello";
        if(c==d)
        {
            System.out.println("c=d");
        }
        else
        {
            System.out.println("c!=d");
        }

当intern函数关闭时,常量池当中并没有c的hello,d也就没法直接用,只能自己再创建,所以c就不等d

当我们打开这个函数时 会手动地把c的hello放到常量池当中去,d去常量池当中看到有hello时就不需要自己再创建了,直接引用,也指向c的对象,所以c=d

public static void main(String[] args) {
        String c=new String("hello");
       c=c.intern();
        String d="hello";
        if(c==d)
        {
            System.out.println("c=d");
        }
        else
        {
            System.out.println("c!=d");
        }

三.字符串的不可变性

String 是不可变对象,字符串中的内容不可以修改。

那么字符串为什么是不可变的呢?

 final修饰引用类型表示不能再引用其他的对象,但引用的内容可以修改。

public static void main(String[] args) {
        final int[]arr={1,2,3,4};
        arr=null;//这行代码会报错,arr已经引用数组,不能再引用其他内容,
        
        arr[0]=2;引用的内容可以变化
        System.out.println(arr[0]);
    }

 字符串的修改

尽量 避免直接对String类进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。

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

    }
}

我们将汇编过程用代码展现一下:

 public static void main2(String[] args) {
        String str="";
        int i=0;
        for(i=0;i<100;i++)
        {
            StringBuilder sb=new StringBuilder();
            sb.append(str);
            sb.append(i);
            sb.toString();
        }
    }

 由汇编和代码我们可以看到每次修改字符串都会新建一个StringBuidler对象,而且每次都会产生新的String对象,效率非常低下 

像这种字符串的修改,因为String类没法直接修改,每次修改会创建新对象,效率低下

String为什么被设计成不可变的?

    (1)线程安全:可以避免线程安全问题

       (2)安全性:在某种程度上可以防止意外修改,在一些情况下,可能会导致一些潜在的安全漏洞

       (3)重用和缓存:可以将字符串放在常量池中,避免重复创建新的字符串,节省内存,提高效率。

    (4)代码设计简化

四.StringBuilder/StringBuffer

常用方法:

像这种字符串的修改我们通常用StringBuilder 和StringBuffer    

 public static void main8(String[] args) {
        StringBuilder a=new StringBuilder("edf");
        for (int i = 0; i < 4; i++) {
            a.append(i);//对字符串进行追加


        }
        //System.out.println(a);
        String s=a.toString();
        System.out.println(s);


    }

 

public static void main(String[] args) {
        String s="world";
        StringBuffer c=new StringBuffer(s);
        c.append(129);
        System.out.println(c);


    }

 

我们来看一下用StringBuilder或StringBuffer修改字符串和用String它们的效率之比:

public static void main1(String[] args) {
        long start=System.currentTimeMillis();
        String str="";
        int i=0;
        for(i=0;i<10000;i++)
        {
            str+=i;
        }
       // System.out.println(str);
        long end=System.currentTimeMillis();
        System.out.println(end-start);
    }

 public static void main3(String[] args) {
        String str="";
        long start=System.currentTimeMillis();
        StringBuilder  sb=new StringBuilder();
        sb.append(str);

        int i=0;
        for(i=0;i<10000;i++)
        {
            sb.append(i);

        }
        long end=System.currentTimeMillis();
        System.out.println(end-start);
    }

String 和StringBuilder不能直接转换:

1.String变成StringBuilder ,用StingBuilder的构造方法或append()方法

2.StringBuilder变成String,用toString()方法

String和StringBuilder的区别

String中的内容不可以修改,而StringBuilder中的内容可以修改

String、StringBuilder、StringBuffer的区别

String的内容不可以修改,StringBuilder和StringBuffer可以修改

StringBuffer使用synchronized加锁属于线程安全操作,单线程环境下,性能相较于StringBuilder低一些,StringBuilder未加锁,属于线程不安全操作

 

五.String类的底层是基于数组(字符或字节数组)和字符串常量池,利用不可变性(final)修饰提供了安全、高效的字符串操作

JDK 9之前String类是使用char[](字符数组)存储的,而JDK9之后String使用byte[](字节数组)进行存储,一个char等于两个byte字节,使用byte[]数组可以更好节省内存空间。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值