JAVA 基础学习笔记(8) String不可变的底层原理以及String的相关方法(下)

前言

写完上篇后,感染了红眼病做啥都没兴趣了,和牙疼一样,不致命但很要命,得亏我好得快☹️

在上篇里我只是提了提说用变量名去拼接字符串会创建新对象,但并没有解释原理,这里正好可以补充补充

StringBuilder

当我们需要频繁地对字符串进行修改时,使用 Java 的 StringBuilder 类可以提供更高效的处理方式。StringBuilder 是一个可变的字符串序列,它允许对字符串进行动态修改,而无需创建新的字符串对象。
对之前的变量名拼接的代码进行调试
调试代码:

        String str1="你好";//直接赋值
        String str2=new String("你好");//常用构造器赋值
        String str3=str1+str2;

第一层进入StringBuilder构造器,创建了一个StringBuilder对象,

public StringBuilder() {
        super(16);
    }

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity specified by the {@code capacity} argument.
     *
     * @param      capacity  the initial capacity.
     * @throws     NegativeArraySizeException  if the {@code capacity}
     *               argument is less than {@code 0}.
     */

第二层:进入append方法,这里会执行两次,一次是str1,一次是str2

 @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

第三层:注意这里是StringBuilder的toString方法,方法里有new String语句,说明新创建了一个String对象,然后又将这个String对象给了str3去引用

    @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

我们再来看看StringBuilder类的属性,这里我直接跳到了它的父类AbstractStringBuilder,StringBuilder非继承的属性不是很重要

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;
	...

容量自动扩展:StringBuilder 内部维护了一个字符数组(char[]),用于存储字符串内容。它的容量会根据需要自动进行扩展,可以容纳任意长度的字符串。
在其他地方我们经常能看到说StringBuilder能减少创建中间对象从而而提高性能,可是我开始还有点疑问,这里不是也创建了对象吗?后来才发现它是为了迎合我的String类的str3,它原本是StringBuilder类的,转换成String当然要新建对象喽

提高性能的案例:

String类叠加字符串hello一万次

public static void main(String[] args) {
        int iterations = 10000;
        String result = "";
        long startTime = System.nanoTime();

        for (int i = 0; i < iterations; i++) {
            result += "Hello";
        }

        long endTime = System.nanoTime();
        long duration = endTime - startTime;

        System.out.println("Result length: " + result.length());
        System.out.println("Duration: " + duration + " nanoseconds");
    }

运行结果:单位是纳秒
`
StringBuilder类叠加字符串hello一万次

public static void main(String[] args) {
            int iterations = 10000;
            StringBuilder result = new StringBuilder();

            long startTime = System.nanoTime();

            for (int i = 0; i < iterations; i++) {
                result.append("Hello");
            }

            long endTime = System.nanoTime();
            long duration = endTime - startTime;

            System.out.println("Result length: " + result.length());
            System.out.println("Duration: " + duration + " nanoseconds");
        }

运行结果:
在这里插入图片描述
次数越多,性能提升越明显

StringBuffer

当涉及到在多线程环境下进行字符串操作时,可以使用 Java 中的 StringBuffer 类。StringBuffer 是一个线程安全的可变字符串类,它与 StringBuilder 类似,但具有同步方法,可以保证线程安全性。
通俗一点来讲,就是StringBuilder的性能减少一点,把线程安全给加上去
看一下它的类属性,它也是AbstractStringBuilder的子类,和 StringBuilder同一个父亲生的,所以很相似

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    static final long serialVersionUID = 3388685877147921107L;

	...
}

主要看它的类方法
在这里插入图片描述
和StringBuilder的多了个synchronized修饰,也就是提高线程安全的修饰符。

性能考虑:由于 StringBuffer 是线程安全的,它在多线程环境下的性能可能会受到一定的影响。因为需要进行同步操作来确保线程安全,这可能会引入一些性能开销。如果不需要考虑线程安全,可以使用 StringBuilder 类,它是一个非线程安全的可变字符串类,性能上可能更好。

String常用构造方法

String(): 无参构造方法,创建一个空字符串对象。

String str = new String();

String(byte[] bytes): 使用指定的字节数组创建字符串对象。根据默认字符集将字节数组转换为字符串。

byte[] byteArray = {97, 98, 99, 100}; // ASCII码对应的字节数组 [a, b, c, d]
String str = new String(byteArray);

String(byte[] bytes, Charset charset):使用指定的字节数组和字符集创建字符串对象。

byte[] byteArray = {97, 98, 99, 100}; // ASCII码对应的字节数组 [a, b, c, d]
Charset charset = Charset.forName("UTF-8");
String str = new String(byteArray, charset);

String(char[] value): 使用指定的字符数组创建字符串对象。

char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str = new String(charArray);

String(char[] value, int offset, int count): 使用指定的字符数组的子数组创建字符串对象。

char[] charArray = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
String str = new String(charArray, 6, 5); // 从索引6开始取5个字符,得到 "World"

String(String original): 使用指定字符串创建一个新的字符串对象,字符串内容和原始字符串相同。

String original = "Hello";
String str = new String(original);

String(StringBuffer buffer): 使用指定的 StringBuffer 对象创建字符串对象。

StringBuffer buffer = new StringBuffer("Hello");
String str = new String(buffer);

String(StringBuilder builder): 使用指定的 StringBuilder 对象创建字符串对象。

StringBuilder builder = new StringBuilder("Hello");
String str = new String(builder);

String常用操作字符串方法

length(): 返回字符串的长度。

String str = "Hello";
int length = str.length(); // 返回 5

charAt(int index): 返回指定索引位置的字符。

String str = "Hello";
char ch = str.charAt(1); // 返回 'e'

substring(int beginIndex): 返回从指定索引开始到字符串末尾的子字符串。

String str = "Hello, World!";
String subStr = str.substring(7); // 返回 "World!"

substring(int beginIndex, int endIndex): 返回从指定的开始索引到结束索引的子字符串。

String str = "Hello, World!";
String subStr = str.substring(7, 12); // 返回 "World"

concat(String str): 将指定的字符串连接到原始字符串的末尾。

String str1 = "Hello";
String str2 = str1.concat(", World!"); // 返回 "Hello, World!"

replace(char oldChar, char newChar): 将字符串中的所有旧字符替换为新字符。

String str = "Hello";
String newStr = str.replace('e', 'a'); // 返回 "Hallo"

toLowerCase(): 将字符串中的所有字符转换为小写。

String str = "Hello";
String lowerCaseStr = str.toLowerCase(); // 返回 "hello"

toUpperCase(): 将字符串中的所有字符转换为大写。

String str = "Hello";
String upperCaseStr = str.toUpperCase(); // 返回 "HELLO"

trim(): 移除字符串两端的空格。

String str = "  Hello  ";
String trimmedStr = str.trim(); // 返回 "Hello"

split(String regex): 将字符串拆分为子字符串数组,根据指定的正则表达式作为分隔符。

String str = "Hello,World,Java";
String[] arr = str.split(","); // 返回包含三个元素的字符串数组: ["Hello", "World"]

还有很多其他方法遇到查就是了

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

罗不丢

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

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

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

打赏作者

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

抵扣说明:

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

余额充值