【JavaSE】String类

目录

一、创建字符串 

1.1 字符串常量池

1.2常见的三种创建字符串的方式以及每种方式下的内存布局

①String str = "hello java";

②String str = new String("hello java");

③char[] array = {'a','b','c'};String str3 = new String(array);

1.3 理解字符串不可变

疑问:如果想要修改字符串,该怎么办?

注意:这样写代码会出现大量的临时对象,效率比较低,不建议这样写。

1.4 总结

二、字符串比较相等

2.1 常见题型

实例一:

实例二:

实例三:

实例四:

实例五:

实例六:

实例七:

实例八:

实例九:

实例十:

2.2 总结

三、字符、字节和字符串

3.1 字符和字符串

3.2 字节和字符串

3.3 总结

四、字符串常见操作

4.1 字符串比较

4.2 字符串查找

4.3 字符串替换

4.4 字符串拆分

4.5 字符串截取

4.6 其他方法

五、StringBuffer和StringBuilder

5.1 StringBuffer和StringBuilder的定义及与String的区别

5.2 StringBuffer和StringBuilder与String之间的转换

5.3 StringBuffer与StringBulider的区别

5.4 总结


一、创建字符串 

1.1 字符串常量池

“池”是编程中一种常见的、重要的提高效率的方式。字符串常量池就是用来存储字符串的。在编译的过程中,如果编译器拿到一个字符串,先去字符串常量池中查找该字符串是否存在,如果不存在,就入池。如果存在,就不会入池。

在JVM中,并没有划分区域,说这块内存就是字符串常量池。在设计时,是用一个哈希表来存储字符串常量。

1.2常见的三种创建字符串的方式以及每种方式下的内存布局

①String str = "hello java";

 在这种创建方式下,str是个引用变量,存储的是字符串在字符串常量池中的地址

②String str = new String("hello java");

在这种方式下,str2中存的是对象的地址。 

备注:String类中的value属性,可以查看源码。

③char[] array = {'a','b','c'};String str3 = new String(array);

1.3 理解字符串不可变

字符串是一种不可变对象,他的内容不可改变。

String类的内部实现是基于char[]来实现的,但是String类并没有提供set之类的方法来修改内部的字符数组。

    public static void main(String[] args) {
        String str = "hello";
        str = str + "java";
        str += "!!!";
        System.out.println(str);
    }

表面上是修改了字符串,其实并不是,内存变化如下:

 运行结果:hellojava!!!。不是String对象本身发生变化,而是str引用了其他的对象。

疑问:如果想要修改字符串,该怎么办?

方法1:借助原字符串

    public static void main(String[] args) {
        String str = "hello";
        str = "H" + str.substring(1);
        System.out.println(str);
    }

这种改法,还是产生了一个新的对象,并没有在原来hello上将h改为H

方法2:借助反射。

是Java类的一种自省的方式。通常情况下,类的内部细节,有时在类外是看不到的,但是通过反射就可以看到。

注意:这样写代码会出现大量的临时对象,效率比较低,不建议这样写。

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

建议的写法

// 建议写法
    public static void main(String[] args) {
        String str1 = "hello";
        StringBuffer sb = new StringBuffer();
        sb.append(str1);
        for(int i = 0;i<1000;i++){
            sb.append(i);
        }
        str1 = sb.toString();
        System.out.println(str1);
    }

1.4 总结

①了解创建字符串的三种对象的方式以及每种方式下的内存分布。

②理解字符串的不可变性。

二、字符串比较相等

2.1 常见题型

实例一:

    public static void main(String[] args) {
        String str1 = "hello java";
        String str2 = new String("hello java");
        System.out.println(str1 == str2);
    }

结果为false 。str1存的是“hello java”在字符串常量池中的地址,str2中存的是new的对象的地址,所以str1和str2不相等。

实例二:

    public static void main(String[] args) {
        String str1 = "hellojava";
        String str2 = "hello"+"java";
        System.out.println(str1 == str2);
    }

结果为true。

首先,常量在编译的时候就已经被运算了,所以str2=“hellojava”。

补充一个知识点:采用直接赋值的方式进行String类的实例化,如果字符串的内容在字符串常量池中不存在,会被自动保存到字符串常量池中;如果存在,就直接引用已经存在的字符串。

因此,str1和str2指向的是同一个对象,str1=str2.

实例三:

    public static void main(String[] args) {
        String str1 = "hellojava";
        String str2 = "hello";
        String str3 = str2 +"java";
        System.out.println(str1 == str3);
    }

运行结果是false,hellojava、hello、java三个字符串入池,str3是个变量,在编译时不知道里面的值,得等到程序运行时才知道。执行第三行代码,hello和java会在堆里面重新生成一个新对象,str3指向这个对象。因此,str1不等于str3.

实例四:

    public static void main(String[] args) {
        String str1 = "hellojava";
        String str2 = "hello" + new String("java");
        System.out.println(str1 == str2);
    }

 运行结果:false。new string("java")后,在堆里面new了一个对象,对象实例化需要用到“java”,对象的成员方法value里面存的“java”的地址。执行第二行代码,刚刚new的String对象和“hello”重新组成了一个新对象,里面存的值时hellojava,str2指向该对象。

实例五:

    public static void main(String[] args) {
        String str1 = "hellojava";
        String str2 = new String("hello") + new String("java");
        System.out.println(str1 == str2);
    }

运行结果:false。new的两个对象指向java和hello。这两个对象组成一个新对象,str2指向这个新对象。

实例六:

   public static void main(String[] args) {
        String str1 = "hello java";
        String str2 = new String("hello java");
        str2.intern();
        System.out.println(str1 == str2);
    }

 运行结果:false。str2.intern()方法就是将str2放入字符串常量池,如果str2所指的字符串在池中不存在,就入池,如果存在,就不入池。所以str1不等于str2.

实例七:

    public static void main(String[] args) {
        String str1 = new String("aa") + new String("bb");
        str1.intern();
        String str2 = "aabb";
        System.out.println(str1 == str2);
    }

运行结果为true。"aa","bb"先入池,new的两个对象分别指向 "aa"和"bb",两个对象组成一个新对象,里面的值时"aabb",此时"aabb"在堆里,执行intern()后,"aabb"入池,执行str2="aabb"时,先在池里查找,发现"aabb"存在,str2就直接指向池里面的"aabb".str1和str2指向的是同一个对象,所以str1=str2.

实例八:

    public static void main(String[] args) {
        String str1 = new String("aa") + new String("bb");
        String str2 = "aabb";
        str1.intern();
        System.out.println(str1 == str2);
    }

 运行结果:false。在执行完 String str2 = "aabb"后,字符串常量池中已经有了"aabb",执行str1.intern(),str1指向的对象无法入池,所以str1指向不变。

实例九:

    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = str1; // str2指向str1指向的对象
        str1 = "java";
        System.out.println(str1 == str2);
    }

 运行结果:false。

实例十:

    public static void main(String[] args) {
        String str = "hello";
        func(str);
        System.out.println(str);
    }
    public static void func(String str) {
        str = "java";  // 修改的是形参的引用
    }

 运行结果:false。

2.2 总结

这块比较的情况比较复杂,建议画图来分析。

三、字符、字节和字符串

3.1 字符和字符串

字符串内部包含一个字符数组,String可以和char[]相互转换。

方法名称类型描述

public String(char value[])

构造将字符数组中的所有内容变成字符串

public String(Char value[],int offset,int count)

构造将字符数组中的部分内容变成字符串
public char charAt(int index)普通获得指定索引位置的字符,索引从0开始
public char[] toCharArray()普通 将字符串变成字符数组返回
    public static void main(String[] args) {
        char[] ch = {'a','b','c','1','2','d'};
        String str1 = new String(ch);
        System.out.println(ch);    // 运行结果:abc12d
        String str2 = new String(ch,1,4);
        System.out.println(str2);  // 运行结果:bc12
        for (int i = 0; i < str1.length(); i++) {
            System.out.println(str1.charAt(i));
        }
        char[] ch2 = str2.toCharArray();
        System.out.println(ch2[0]);    
    }
// 判断一个字符串是否全部由数字组成
    public static void main(String[] args) {
        String str = "1a23456";
        System.out.println(isNumber(str) ? "全部由数组组成":"不是全部由数字组成");;

    }

    private static boolean isNumber(String str) {
        for (int i = 0; i < str.length(); i++) {
            if(str.charAt(i) < '0' || str.charAt(i) > '9'){
                return false;
            }
        }
        return true;
    }

3.2 字节和字符串

字节常用于数据传输以及编码转换的处理之中,String也能方便的和byte[]相互转换。

方法名称类型描述

public String(byte bytes[])

构造将字节数组中的所有内容变成字符串

public String(byte bytes[],int offset,int length)

构造将字节数组中的部分内容变成字符串
public byte[] getBytes()普通将字符串以字节数组的形式返回
public byte[] getBytes(String charsetName) throws普通 编码转换处理
    public static void main(String[] args) {
        byte[] bytes = {97,98,99,100};
        String str1 = new String(bytes);
        System.out.println(str1);     // 运行结果:abcd
        String str2 = new String(bytes,1,2);
        System.out.println(str2);     // 运行结果:bc
        byte[] bytes2 = str2.getBytes();
        System.out.println(Arrays.toString(bytes2));  //运行结果:[98, 99]
        String str3 = "world";
        byte[] bytes3 = str3.getBytes();
        System.out.println(Arrays.toString(bytes3));  //[119, 111, 114, 108, 100]
    }

3.3 总结

byte[]是把String按照一个字节一个字节的方式处理,这种适合在网络传输、数据存储这样的场景下使用,更适合针对二进制数据来操作。

char[]是把String按照一个字符一个字符的方式处理,更适合针对文本数据来操纵,尤其是包含中文的时候。

四、字符串常见操作

4.1 字符串比较

方法名称类型描述

public boolean equals(Object obj)

普通区分大小写的比较
public boolean equalsIgnoreCase(String str)普通不区分大小写的比较
public  int compareTo(String str)普通 比较两个字符串的大小关系
public static void main(String[] args) {
        String str1 = "abcd";
        String str2 = "ABCD";
        System.out.println(str1.equals(str2));    //false
        System.out.println(str1.equalsIgnoreCase(str2)); // true
        System.out.println(str1.compareTo(str2));  //32
        // 如果前n个字符相同,就从第n+1个开始比较
        String str3 = "abcde";
        String str4 = "abcdf";
        System.out.println(str3.compareTo(str4));  // -1
        // 如果两个字符串长度不一样,返回的是长度差
        String str5 = "abcde";
        String str6 = "abcdefd";
        System.out.println(str5.compareTo(str6));  // -2
    }

equals方法是比较是否相等,compareTo比较的是大小。

4.2 字符串查找

方法名称类型描述

public boolean contains(CharSequence s)

普通判断一个子字符串是否存在
public int indexOf(String str)普通从头开始查找指定字符串的位置,查到了返回位置的开头索引,如果查不到就返回-1
public int indexOf(String str,int fromIndex)普通从指定位置开始查找子字符串位置
public int lastIndexOf(String str)普通从后向前查找子字符串位置
public int lastIndexOf(String str,int fromIndex)普通 从指定位置后向前查找子字符串位置
public boolean startsWith(String prefix)普通判断是否以指定字符串开始
public boolean startsWith(String prefix,int tooffset)普通从指定位置判断是否以指定字符串开始
public boolean endsWith(String prefix)普通判断是否以指定字符串结尾
public static void main(String[] args) {
        String str1 = "abcdabcdef";
        System.out.println(str1.contains("ab"));  // true
        // 如果内容重复,他只能返回查找的第一个位置
        System.out.println(str1.indexOf("ab"));   // 0
        System.out.println(str1.indexOf("ab", 2)); // 4
        // 如果找不到,返回-1
        System.out.println(str1.indexOf("abf"));  //-1
        System.out.println(str1.lastIndexOf("cd"));  //6
        System.out.println(str1.lastIndexOf("cd", 4));  //2
        System.out.println(str1.startsWith("ab"));  // true
        System.out.println(str1.startsWith("ab", 1)); // false
        System.out.println(str1.endsWith("ef"));   // true
    }

4.3 字符串替换

方法名称类型描述

public String replaceAll(String str1,String str2)

普通替换指定的位置
public String replaceFirst(String str1,String str2)普通替换首个位置
    public static void main(String[] args) {
        String str1 = "abcdabcdab";
        String str2 = str1.replace("b","q");  // 不会修改原本的String对象,会创建一个新的
        System.out.println(str2);   // aqcdaqcdaq
        String str3 = str1.replaceFirst("a","g");  
        System.out.println(str3);  // agcdabcdab
    }

注意:由于String是不可变对象,替换不会修改当前字符串,而是产生一个新的字符串。

4.4 字符串拆分

方法名称类型描述

public String[] split(String str)

普通将字符串全部拆分
public String split(String str,int limit)普通将字符串部分拆分,数组长度就是limit极限
public static void main(String[] args) {
        String str1 = "ab cd ef";
        String[] result = str1.split(" ");
        System.out.println(Arrays.toString(result));  // [ab, cd, ef]
        String str2 = "ab cd ef";
        String[] result2 = str1.split(" ",2);
        System.out.println(Arrays.toString(result2));  // [ab, cd ef]
        // 有些特殊字符作为分隔符可能无法正常的进行切分,需要加上转义
        String str3 = "127.0.0.1";
        String[] str4 = str3.split("\\.");   //[127, 0, 0, 1]
        System.out.println(Arrays.toString(str4));  
        
    }

注意:

字符:"|"  "*"  "+"都得加上转义字符,前面加上"\\".

而不是"",就得写成"\\"

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

4.5 字符串截取

方法名称类型描述

public String subString(int beginIndex)

普通从指定索引到结尾
public String subString(int beginIndex,int endIndex)普通截取部分内容
    public static void main(String[] args) {
        String  str = "helloWorld";
        System.out.println(str.substring(3));  // loWorld
        System.out.println(str.substring(4, 5));  // o 
    }

注意:

索引从0开始。

区间前闭后开。

4.6 其他方法

方法名称类型描述

public String trim()

普通去掉字符串中的左右空格,保留中间空格
public String toUpperCase()普通字符串转大写
public String toLowerCase()普通字符串转小写

public native String intern()

普通字符串入池操作
public String concat(String str)普通字符串入池
public int length()普通取得字符串长度
public boolean isEmpty()普通判断是否为空字符串,但不是null,而是指长度为0

五、StringBuffer和StringBuilder

5.1 StringBuffer和StringBuilder的定义及与String的区别

从第一小节的介绍我们可以知道,任何的字符串常量都是String对象,String对象不可变。为了方便对String的修改,提供了StringBuffer和StringBuilder类。

同时,String是通过 + 完成字符串的拼接,StringBuffer和StringBuilder是通过append方法完成字符串的拼接。

 public static void main(String[] args) {
        // StringBuffer和StringBuilder功能类似,以StringBuffer为例
        // StringBuffer 连接字符串使用 append
        StringBuffer sb = new StringBuffer();
        sb.append("hello");
        sb.append("java").append(1);
        System.out.println(sb);
        // String连接字符串使用 +
        String str1 = "java";
        str1 += "hello";
        System.out.println(str1);
    }

综上所述,区别如下:

String:不可修改,通过 + 完成字符串的拼接

StringBuffer和StringBuilder:可以修改,通过append方法完成字符串的拼接。同时StringBuffer也有一些String没有的方法。

5.2 StringBuffer和StringBuilder与String之间的转换

StringBuffer和StringBuilder转为String:调用toString方法

String转为StringBuffer和StringBuilder:调用构造方法

public static void main(String[] args) {
        // String 转StringBuffer
        StringBuffer sb2 = new StringBuffer("hello");
        System.out.println(sb2);
        // StringBuffer 转String
        String str = sb2.toString();
        System.out.println(str);
    }

5.3 StringBuffer与StringBulider的区别

StringBuffer和StringBuilder的大部分功能是类似的。

StringBuffer采用同步处理,属于线程安全操作;StringBuilder未采用同步处理,属于线程不安全操作。

5.4 总结

①String的内容不可改,StringBuilder和StringBuffer可改。

②String转StringBuilder或StringBuffer,调用StringBuilder或StringBuffer的构造方法。

   StringBuilder或StringBuffer转String,调用toString方法。

③ StringBuilder和StringBuffer有一些String没有的操作字符串的方法。

④连接字符串,String采用+,StringBuilder和StringBuffer采用append方法。

⑤StringBuilder线程不安全,StringBuffer线程安全。

  

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

刘减减

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

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

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

打赏作者

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

抵扣说明:

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

余额充值