为什么stringbuffer最终?

时间:2015-04-10 17:46:22

标签: java

字符串类是不可变的,其背后的原因之一是该类被声明为final,尽管还有其他原因。 但是为什么StringBuffer或StringBuilder最终仍然是可变的? 那么还有哪些因素决定String是不可变的呢?

7 个答案:

答案 0 :(得分:5)

StringBufferStringBuilder主要用于单个方法中的字符串连接操作,使用它们的代码通常由编译器生成。因此,扩展并不是典型的用例。

另一方面,final允许在JVM中进行更好的优化,至少在过去是这样;今天的HotSpot JVM不需要它,但是,从来没有理由改变这些类的final声明。

请注意,扩展StringBuilder和覆盖多态行为的方法会有点无意义,因为整个JRE中没有public方法接受或返回StringBuilder实例(除{{1}之外) 1}}本身)。 AppendableCharSequence填补了这一空白,提供了更大的灵活性。

mutability immutability 的概念与StringBuilder类的概念完全不同。它们只取决于一个类提供的方法或操作。在finalString拥有此类方法时,StringBuffer没有允许修改其内容的方法。声明一个不可变的类StringBuilder只是有助于禁止可能引入支持变异的方法的子类,但这并不是一个硬性要求。

答案 1 :(得分:2)

为什么String是final和immutable实际上是两个,部分独立的问题。

首先,String是java.lang包的一部分,顾名思义,此包中的类型与实现java语言到其定义有关。 这是最终的一个原因,如果我接受一个字符串,我可以依赖行为,因为java语言定义了一个字符串行为(因为你不能创建自己的具有不同行为的子类。)

其次,String的不变性是“只是”一种设计选择,但是当你在某处传递一个String时(例如作为文件名),它再次具有有利意义,所谓的API可以确保你无法改变字符串并直接存储对它的引用(而不是如果它是可变的则复制它)。它还显着简化了在多线程环境中使用String的过程。

那么为什么StringBuilder / Buffer最终?这又是“只是”一个设计选择,但没有像String那样强大而明显的理由。他们就这样做了。

答案 2 :(得分:1)

我认为你对"最终"有误解。与class一起使用时的关键字。 当一个变量被声明为final时,它的值在初始化后就不会改变。

即。

final int i=5;
      i++// Will give an error.

<强>可是:

如果是课程: 最终关键字服务器的目的是使类不可继承,即该类不能被分类! 即。

final class question
{}
class answer extends question//Will give an error!!!
{}

回答您的问题:

现在,你是对的,字符串是不可变的,因为一旦字符串对象被初始化,它就不能被改变而且Stringbuilder和Stringbuffer是可变的(Vice-Versa),这与这些类无关最后! 你没有正确地对它们进行分类!

我希望我帮忙!

修改

我想我应该完全解释一下Stringbuilder是如何可变的而String不是:

我将通过代码解释此代码:

Stringbuilder a = new Stringbuilder("a");//Initial String!!
a.append("b"); //Now the String is ab!!

因此,由于同一个对象,即 a 的值被改变,因此它被称为可变的。(一个对象,即在初始化后能够改变其值)。

现在字符串:

String a = "a";
a = a + "b"; //Explained below.

虽然对你来说这可能看起来字符串对象 a 正在改变它的值,因此它是可变的,但它不是,因为后面的Stringbuilder正在工作。 即 上面代码中编译器所做的实际操作是:

a = new StringBuilder(a.append("b")); //The actual code...

所以,现在变量 a 存储值&#34; ab&#34;。 我知道这很令人困惑,但是如果你准确地阅读我的代码,你会发现对象 a 从未改变它的值,它只是被分配了一个新值! 这就是所谓的不可变因素,即初始化后对象无法改变!

我希望我帮助

答案 3 :(得分:1)

String不是永恒的,因为它是最终的; final和不变性或多或少是正交的。创建一个类final 的一种方法,使一个类不可变,但创建一个类final也是一个好的编程实践的一部分一般而言,无论你想要什么样的行为。

外部用户不能扩展不可变类。它可能在自己的包中有几个实现,例如Guava的ImmutableMap,在这种情况下,课程不一定是最终的,但你也可以禁止延期,例如使构造函数包为private,因此包外的用户不能扩展该类。

final类是任何无法扩展的类。这是有效Java中许多案例中的推荐做法 - 也就是说,只要您没有明确的理由使该类成为可子类化的,那么将其作为最终通常是一种很好的做法。

答案 4 :(得分:0)

如果你担心的是扩展StringBuilder或StringBuffer的行为,你仍然可以做到 - 只是不通过继承。你可以组成或授权。类String,StringBuffer,StringBuilder都实现了CharacterSequence。因此,创建实现CharacterSequence的类,并将所有方法委托给组合的StringBuffer或StringBuilder。继承的构成是GoF的黄金法则 - 请参阅此discussion

使一个类最终是一个额外的,更有效的封装层 - 也许代码的作者不觉得任何人应该通过扩展来修改行为,因为他/她可能觉得该类的子类可能不是真正代表自己(就转换而言)。

答案 5 :(得分:0)

StringBuffer是可变字符串的概念,它是线程安全的,也就是说,对它执行的所有操作都是同步的。

StringBuilder建议替换StringBuffer。当它出现时,它被引入,当涉及到字符串时,不经常使用同步。

String只是String。为什么它是不可变的?也许原因是线程安全和成本。如果您想存储全球String只读,该怎么办?如果它是可变的,则所有读取必须已经同步 - 这是额外的开销,这在此是不必要的。

这就是提供这三个课程的原因 - 选择了你想要支付的费用。

如您所述,所有这些课程 - StringStringBuilderStringBuffer都是最终的。原因是你不能(并且不应该)修改这些类的行为。

最好实现另一个类,它包含(例如)StringBuilder并提供类似的功能,而不是扩展它。

如果需要,您可以通过实现CharSequence来提供类似的功能 - 所有这些类都实现了此接口。

答案 6 :(得分:0)

那么还有哪些因素决定String是不可变的?

答案很简单,因为String类的所有数据成员都是final,这使得它成为不可变的。

如果要使自己的类不可变,请将该类的所有数据成员设为final。并初始化构造函数中的所有最终数据成员,以便一旦初始化,就永远不会更改。

如果你会看到 String 类实现不变性,你会发现:

private final char[] value;

值的初始化将在构造函数部分中进行:

public String(String toCopy){

     value = toCopy.value;

}

如果您将看到 StringBuffer 类实现,您会发现:

private char[] value;

public StringBuffer(String toCopy){

     value = toCopy.value;

}

因此,在上面的代码中,您可以看到, String 类的数据成员将初始化并且永远不会更改,但 StringBuffer class的 value 数据成员可以多次初始化和更改。

因此,这使String类不可变,不会使类最终。