关于String类思考(一):不可变

一.String不可变

         String对象在创建后不能被修改。这种不可变性可以带来一些性能优势和安全性。那么为什么String类是不可变的呢?下面是从源码角度解释原因:

        String类的成员变量是一个char数组,它被声明为

private final char[] value

       从源代码来看, 这个char数组存储了String对象的字符内容,因为它被声明为final,所以一旦被初始化,就不能再被修改。而且,String类中没有任何公共方法可以修改该数组。当需要对String对象进行修改时,String类的实现不是修改原始对象,而是创建一个新的String对象,并将修改后的结果存储在其中。例如,当我们调用String类的replace()方法来替换字符串中的某些字符时,它并不会修改原始字符串,而是创建一个新的字符串对象来存储替换后的结果,从而保证了String对象的不可变性。

二.为什么String要被设计成不可变呢?

        安全性:由于字符串是Java中最广泛使用的对象之一,String对象被广泛用于很多重要的任务,比如密码验证等。如果String是可变的,那么在多线程环境下,如果有多个线程同时修改同一个String对象,就会造成不可预料的结果,这对程序的安全性是非常不利的。

        性能:在Java中,String对象经常被用作哈希表中的键,如果String是可变的,那么每次修改String对象都需要重新计算哈希值,这会带来很大的性能损失。此外,由于String不可变,Java编译器可以在编译时进行优化,例如字符串常量的拼接,编译器可以在编译时直接将多个字符串常量拼接成一个字符串常量,从而避免在运行时进行字符串拼接操作,提高程序的性能。

        简单性:String类的不可变性使得程序的设计更加简单,因为String对象可以被自由地传递和共享,而不必担心它们会被修改。

三.不可变带来的问题

        虽然String类的不可变性在很多情况下都是非常有益的,但是也会带来一些问题,具体包括以下几个方面:

内存浪费:由于String对象是不可变的,每次修改String对象都需要创建一个新的String对象,这就会带来很多的内存开销。例如,在进行字符串拼接操作时,每个中间结果都需要创建一个新的String对象,这会导致大量的内存浪费。

性能问题:虽然String的不可变性有助于提高程序的性能,但在某些情况下,它也可能会导致性能问题。例如,在进行字符串拼接操作时,由于每个中间结果都需要创建一个新的String对象,这会导致大量的对象创建和垃圾回收操作,从而降低程序的性能。

安全问题:虽然String对象的不可变性有助于提高程序的安全性,但在某些情况下,它也可能会导致安全问题。例如,在使用String对象作为密码时,由于String对象是不可变的,密码可能会在内存中被暴露,从而被其他人获取。为了解决这个问题,可以使用char数组来代替String对象。

难以扩展:由于String对象是不可变的,它的值无法被修改,这也意味着String对象的功能也无法被扩展。例如,在String对象中增加一个新的方法是不可能的,这限制了String对象的功能扩展能力。

四.解决思路:StringBuffer和StringBuilder

      StringBuffer和StringBuilder是Java中两个用于字符串操作的类,它们都比String类更加灵活和高效。它们的主要区别在于线程安全性和性能。

 StringBuffer源代码

public final class StringBuffer
 extends AbstractStringBuilder
 implements java.io.Serializable, CharSequence
{
 private static final long serialVersionUID = 3388685877147921107L;
 public synchronized StringBuffer append(Object obj) {
 super.append(String.valueOf(obj));
 return this;
 }
 public synchronized StringBuffer append(CharSequence s) {
 super.append(s);
 return this;
 }
 public synchronized StringBuffer append(CharSequence s, int start, int end) {
 super.append(s, start, end);
 return this;
 }
 public synchronized StringBuffer append(char[] str) {
 super.append(str);
 return this;
 }
 public synchronized StringBuffer append(char[] str, int offset, int len) {
 super.append(str, offset, len);
 return this;
 }
 public synchronized StringBuffer append(boolean b) {
 super.append(b);
 return this;
 }
 public synchronized StringBuffer append(char c) {
 super.append(c);
 return this;
 }
 public synchronized StringBuffer append(int i) {
 super.append(i);
 return this;
 }
 public synchronized StringBuffer append(long lng) {
 super.append(lng);
 return this;
 }
 public synchronized StringBuffer append(float f) {
 super.append(f);
 return this;
 }
 public synchronized StringBuffer append(double d) {
 super.append(d);
 return this;
 }
 public synchronized StringBuffer appendCodePoint(int codePoint) {
 super.appendCodePoint(codePoint);
 return this;
 }
 // 其他方法省略
}

StringBuilder源代码 

public final class StringBuilder
 extends AbstractStringBuilder
 implements java.io.Serializable, CharSequence
{
 private static final long serialVersionUID = 1L;
 public StringBuilder append(Object obj) {
 return append(String.valueOf(obj));
 }
 public StringBuilder append(String str) {
 super.append(str);
 return this;
 }
 public StringBuilder append(StringBuilder sb) {
 super.append(sb);
 return this;
 }
 public StringBuilder append(CharSequence s) {
 if (s == null)
 s = "null";
 return append(s, 0, s.length());
 }
 public StringBuilder append(CharSequence s, int start, int end) {
 super.append(s, start, end);
 return this;
 }
 }

        StringBuffer是一个线程安全的可变字符串类,它的方法都是使用synchronized关键字来保证线程安全的。这也就意味着,虽然StringBuffer可以在多线程环境中使用,但是它的性能会受到一定的影响。在Java 5之前,StringBuffer是Java中操作字符串的主要工具。

        StringBuilder是一个非线程安全的可变字符串类,它的方法没有使用synchronized关键字来保证线程安全。这也就意味着,在单线程环境中使用StringBuilder比使用StringBuffer更加高效。在Java 5之后,StringBuilder成为Java中操作字符串的首选工具。

         以上是两者的源代码实现,可以看出它们的代码实现基本相同,只是StringBuffer中所有的公共方法都添加了synchronized关键字。不考虑线程安全的情况下,StringBuilder效率最高,实际开发中也最常用。在单线程环境中,建议使用StringBuilder;在多线程环境中,建议使StringBuffer。

五:StringJoiner

        Java 8中新增的一个字符串拼接工具类,它提供了一种简单的方式来拼接字符串,并且比较灵活。使用StringJoiner可以将多个字符串拼接成一个字符串,并且可以指定拼接字符串的分隔符、前缀和后缀等等。StringJoiner的主要方法包括:

//创建一个使用指定分隔符的StringJoiner对象。
StringJoiner(CharSequence delimiter);
//创建一个使用指定分隔符、前缀和后缀的StringJoiner对象。
StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix);
//将指定的字符串添加到StringJoiner对象中。
StringJoiner add(CharSequence newElement);
//将另一个StringJoiner对象中的字符串合并到当前对象中。
StringJoiner merge(StringJoiner other);

下面是一个简单的示例:

StringJoiner joiner = new StringJoiner(",", "[", "]");
joiner.add("apple");
joiner.add("banana");
joiner.add("orange");
String result = joiner.toString();
System.out.println(result);
//输出结果为:[apple,banana,orange]

        上面的示例中,我们首先创建了一个使用逗号作为分隔符、方括号作为前缀和后缀的StringJoiner对象。然后,我们将三个字符串(apple、banana和orange)添加到StringJoiner对象中,最后使用toString()方法将其转换成一个字符串。

        本文讨论了String类的不可变以及为什么要设计成不可变和这样所带来的问题,StringBuffer和StringBuilder的对应解决,以及平常很少用的StringJoiner,希望对大家有用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值