Java学习笔记:String、StringBuilder与StringBuffer

String类是Java内置的用来表示字符串的类,所有的字面量字符串,都是String类的实例实现。当然,我们也可以通过new一个新对象的方式,创建一个String实例。

java 复制代码
public class App {  
    public static void main(String[] args) {  
        // 方式1:使用字面量  
        String s1 = "hello";  
        // 方式2:new  
        String s2 = new String("hi");  
    }  
}

需要注意的是,使用字面量创建的字符串,字符串会存储到内存的字符串常量池中。在Java有所谓"享元模式"(共享元素),即两个变量如果引用相同的字符串内容,系统会指向同一个字符串常量池中内的字符串。证明如下:

java 复制代码
public class Demo0 {  
    public static void main(String[] args) {  
        // 用字面量创建一个String对象  
        String s1 = "hello";  
        // 用字面量创建另外一个String对象,字符串内容完全相同  
        String s2 = "hello";  
        // 证明两个变量都是同一个对象的引用  
        System.out.println(s1 == s2); //  true  
    }  
}

而如果不是用的字面量,是用new创建两个String对象,则是完全不同的结果。用new创建两个字符串内容完全相同的String对象,会在内存堆里存储对象。两个变量则是完全不同的对象。证明如下:

java 复制代码
public class Demo1 {  
    public static void main(String[] args) {  
        // 用new创建一个String对象  
        String s1 = new String("hello");  
        // 用new创建另外一个String对象,字符串内容完全相同  
        String s2 = new String("hello");  
        // 证明两个变量是两个对象  
        System.out.println(s1 == s2); //  false  
    }  
}

字符串在编程中,是最常见的几种对象,因此String方法非常非常丰富。String对象是不可变的,其方法产生的字符串,都是返回一个新的String对象。

String常用的方法

String类的常见方法可以划分为基本操作、转换操作、替换与去除、截取与分隔、判断操作等分类。

String类的基本操作方法有:获取字符串长度、返回字符在字符串中第一次、最后一次出现的索引、返回字符串索引上的字符等。

java 复制代码
public class Demo2 {  
    public static void main(String[] args) {  
        String s1 = "hello";  
        // 获取字符串的长度  
        System.out.println(s1.length()); // 5  
        // 返回字符在字符串中第一次出现的索引  
        System.out.println(s1.indexOf('l')); // 2 (索引从0开始)  
        // 返回字符在字符串中最后一次出现的索引  
        System.out.println(s1.lastIndexOf('l')); // 3  
        // 返回指定索引的字符  
        System.out.println(s1.charAt(1)); // e  
    }  
}

String类的转换操作有:将字符串转换为字符数组、将int类型转换为字符串、将字符串中所有字符转换为小写、将字符串中所有字符转换为大写

java 复制代码
public class Demo3 {  
    public static void main(String[] args) {  
        String s1 = "hello";  
        // 将字符串转换为字符数组  
        char[] chs = s1.toCharArray();  
        for (int i = 0; i < chs.length; i++) {  
            System.out.print(chs[i]); // hello  
        }  
        System.out.println();  
        // 将int类型转换为字符串  
        int a = 10086;  
        String s2 = String.valueOf(a);  
        System.out.println(s2); // 10086  
        // 将字符串中的字符全部转换为大写  
        String s3 = s1.toUpperCase();  
        System.out.println(s3); // HELLO  
        // 将字符串中的字符全部转换为小写  
        String s4 = s1.toLowerCase();  
        System.out.println(s4); // hello  
    }  
}

String类的替换去除操作:用新字符串替换原有字符串,得到一个新的字符串;去除字符串首尾的空格。

java 复制代码
public class Demo4 {  
    public static void main(String[] args) {  
        String s1 = "hello";  
        // 用新字符串替换原有字符串,得到一个新的字符串  
        String s2 = s1.replace("hello", "helloworld");  
        System.out.println(s2); // helloworld  
        // 去除字符串首尾的空格  
        String s3 = "  hello  ";  
        String s4 = s3.trim();  // 建议用strip()替代
        System.out.println(s4); // hello  
    }  
}

需要注意:trim()只能去除ASCII码≤32 的空白字符(空格、制表符、换行等),但不能去除全角空格或其他Unicode空白字符。Java 11+引入了strip()方法来解决这个问题。因此,建议使用strip()方法替代trim()方法

String类的截取与分隔操作有:根据参数将原字符串分隔为若干个字符串(字符串数组)、截取从指定索引后的所有字符、截取从指定开始索引到指定结束索引之间的字符。

java 复制代码
public class Demo5 {  
    public static void main(String[] args) {  
        String s1 = "this is a text";  
        // 将原字符串分隔为若干个字符串(字符串数组)  
        String[] arr = s1.split(" ");  
        for (int i = 0; i < arr.length; i++) {  
            System.out.println(arr[i]);  
        }  
        // 截取从指定索引后的所有字符  
        String s2 = "helloworld";  
        System.out.println(s2.substring(5)); // world  
        // 截取从指定开始索引到指定结束索引之间的字符  
        System.out.println(s2.substring(2, 4)); // ll  
    }  
}

String类的判断操作有:判断与指定字符串比较是否相等、判断字符串是否以指定字符串开始、判断字符串是否以指定字符串结尾、判断字符串是否包含指定的字符序列、判断字符串是否为空(字符串长度为0)。

java 复制代码
public class Demo6 {  
    public static void main(String[] args) {  
        String s1 = "hello";  
        // 判断与指定字符串比较是否相等  
        System.out.println(s1.equals("hello")); // true  
        // 判断字符串是否以指定字符串开始  
        System.out.println(s1.startsWith("he")); // true  
        // 判断字符串是否以指定字符串结尾  
        System.out.println(s1.endsWith("lo")); // true  
        // 判断字符串是否包含指定的字符序列  
        System.out.println(s1.contains("llo")); // true  
        // 判断字符串是否为空  
        System.out.println(s1.isEmpty()); // false  
    }  
}

StringBuilder和StringBuffer类

由于String对象是不可变对象,因此String类的所有方法若是返回字符串,都是返回一个新的字符串。由于字符串是高频出现的对象,而因为字符串的不可变特性,对内存的开销较大。

因此,Java系统前后推出了StringBuffer类和StringBuilder类,作为String类的补充。两者都是可变的字符串对象,两者的方法都几乎相同,都是在原字符串上进行变更修改,而不是产生一个新的字符串对象。

以StringBuilder为例,演示StringBuilder和StringBuffer类的常用方法。

java 复制代码
public class Demo7 {  
    public static void main(String[] args) {  
        StringBuffer str = new StringBuffer("hello");  
        // append方法:添加字符串  
        str.append(" world");  
        System.out.println(str); // hello world  
        // insert方法:在指定位置添加字符串  
        str.insert(5, " java's");  
        System.out.println(str); // hello java's world  
        // replace方法:替换字符串  
        str.replace(5, 12, " java");  
        System.out.println(str); // hello java world  
        // delete方法:删除字符串  
        str.delete(5, 10);  
        System.out.println(str); // hello world  
    }  
}

StringBuffer类和StringBuilder类区别在于相对运行快慢和线程安全性,StringBuffer是线程安全的,运行性能比StringBuilder慢。而StringBuilder虽然是线程不安全的,但是优势在于运行速度快。

java 复制代码
package string.demo2;  
  
public class Demo7 {  
    public static void main(String[] args) {  
        StringBuffer str0 = new StringBuffer("hello");  
        StringBuilder str1 = new StringBuilder("hello");  
  
        // 测试StringBuffer对象方法的运行时间  
        long start = System.nanoTime();  
        // append方法:添加字符串  
        str0.append(" world");  
        System.out.println(str0); // hello world  
        // insert方法:在指定位置添加字符串  
        str0.insert(5, " java's");  
        System.out.println(str0); // hello java's world  
        // replace方法:替换字符串  
        str0.replace(5, 12, " java");  
        System.out.println(str0); // hello java world  
        // delete方法:删除字符串  
        str0.delete(5, 10);  
        System.out.println(str0); // hello world  
        long end = System.nanoTime();  
        System.out.println("StringBuffer运行时间:" + (end - start) + "纳秒");  
  
        System.out.println("------------------------------------------------");  
  
        // 测试StringBuilder对象方法的运行时间  
        long start1 = System.nanoTime();  
        str1.append(" world");  
        System.out.println(str1);  
        str1.insert(5, " java's");  
        System.out.println(str1);  
        str1.replace(5, 12, " java");  
        System.out.println(str1);  
        str1.delete(5, 10);  
        System.out.println(str1);  
        long end1 = System.nanoTime();  
        System.out.println("StringBuilder运行时间:" + (end1 - start1) + "纳秒");  
    }  
}
shell 复制代码
hello world
hello java's world
hello java world
hello world
StringBuffer运行时间:398609纳秒
------------------------------------------------
hello world
hello java's world
hello java world
hello world
StringBuilder运行时间:92160纳秒

进程已结束,退出代码为 0

由此可见,StringBuilder确实要更快一些。一般情况下,我们都是单线程运行程序,因此推荐用StringBuilder。

相关推荐
SimonKing4 分钟前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean12 分钟前
Jackson View Extension Spring Boot Starter
java·后端
Seven971 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
皮皮林55111 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河11 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
桦说编程14 小时前
从 ForkJoinPool 的 Compensate 看并发框架的线程补偿思想
java·后端·源码阅读
躺平大鹅16 小时前
Java面向对象入门(类与对象,新手秒懂)
java
初次攀爬者16 小时前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺16 小时前
搞懂@Autowired 与@Resuorce
java·spring boot·后端