4

我不知道如果

String ab = "hello";        //straight initialization

String ab_1 = new String ("hello_1");  //initializing using new

两者都有效,但是

StringBuffer bfr = new StringBuffer("hi");   //works only with new

仅在使用 new 创建时才有效。

为什么 String 可以直接实例化,而 StringBuffer 需要 new 运算符。有人可以解释一下主要原因吗?

4

8 回答 8

6

所有对象都需要用new. 只有原语可以从文字 ( int i = 0;) 中实例化。

唯一的例外是:

  • 字符串,它允许特殊的初始化构造:
   String s = "abc"; //can be instantiated from a literal, like primitives
  • 空实例化:Object o = null;

它在Java 语言规范 #3.10中定义:

文字是原始类型、字符串类型或空类型的值的源代码表示。

注意:数组也有一个专用的初始化模式,但这不是文字:

   int[][] a = { { 00, 01 }, { 10, 11 } };
于 2012-08-16T11:32:09.790 回答
2

使用String s1 = "hello";String s2 = new String("hello");有细微差别。

 public static void main(String[] arg ) {
    String s1 = "Java";
    String s2 = "Java";
    String s3 = new String("Java");
    System.out.println(s1==s2); //true
    System.out.println(s1==s3); //false

    StringBuilder sb = new StringBuilder(25); //initial capacikacity
    sb = new StringBuilder(10);
    sb.append(s1).append(" uses immutable strings.");
    sb.setCharAt(20, 'S');
    System.out.println(sb);
}

在上面的代码中,“Java”被称为字符串文字。为了节省内存,这两次出现在代码中,都是同一个String字面量,所以s1和s2实际上指的是内存中的同一个对象。虽然s1.equals(s3)是真的,但它们不会引用内存中的相同对象,如上所示。

在实践中,我们总是.equals用来比较字符串,它们是不可变的,所以我们不能改变 s1 引用的数据(至少不容易)。但是如果我们能够改变 s1 引用的数据,那么 s2 也会随之改变。

StringBuilder 确实允许您修改底层数据:我们经常使用它来将一个字符串附加到另一个字符串,如上图所示。我们很高兴这StringBuilder sb2 = "what?"是非法的,因为在 StringBuilders 的情况下,让它们中的两个引用相同的数据(意味着 sb1==sb2)更有可能导致 sb1 的更改导致 sb2 的意外更改的问题。

于 2012-08-16T12:01:49.093 回答
1
 String ab = "hello";        //straight initialization
 String ac = "hello";  // create one more reference ac

String是一种特殊情况,当您使用 new 关键字时,将创建一个新的 String 对象。请注意,对象总是在堆上——字符串池不是与堆分开的单独内存区域。字符串池就像一个缓存。

之所以这样,是因为字符串是 java 大量使用的东西,使用 new 关键字创建字符串对象是昂贵的,这也是 java 引入StringPool概念的原因。

如果您声明一个ac具有相同值的变量,java 将不会创建新对象(字符串),它只会引用hello池中已经存在的相同对象()。

 String ab_1 = new String ("hello_1");  //initializing using new

它将简单地在内存中创建对象并ab_1引用该对象。

于 2012-08-16T11:36:27.433 回答
1

字符串在 Java 中是一个非常特殊的情况(在我看来这并不是一件好事,但这并不重要)。

与其他对象不同,字符串可以像常量一样直接实例化。执行此操作时,String 常量将添加到 String 常量池中,并像处理原语一样处理。让我举个例子吧。

String a = "abc";
String b = "abc";

当您实例a化为“原始”字符串时,它会被添加到池中,当您实例化时b,会从池中返回相同的对象,因此如果您这样做:

a == b;

你会得到... true,因为它实际上是同一个对象。如果你用 实例化两者new,你会得到错误的,因为你正在比较两个不同对象的引用(新的强制创建一个不同的对象)。

于 2012-08-16T11:36:49.370 回答
1

基于“存储”字符串的“位置”还有另一个区别 - 内存或字符串常量池。

为了提高 Java 的内存效率,JVM 预留了一个特殊的内存区域,称为“字符串常量池”。当编译器遇到字符串字面量时,它会检查池以查看是否已经存在相同的字符串。如果找到匹配项,则对新文字的引用将定向到现有字符串,并且不会创建新的字符串文字对象。(现有的字符串只是有一个额外的参考。)

String s = "abc"; // creates one String object and one reference variable

在这个简单的例子中,“abc”将进入池中,s 将引用它。

String s = new String("abc"); // creates two objects, and one reference variable

在这种情况下,因为我们使用了 new 关键字,Java 将在普通(非池)内存中创建一个新的 String 对象,s 将引用它。此外,文字“abc”将被放入池中。

于 2012-08-16T11:39:19.253 回答
1

字符串由 java 编译器专门处理。当您键入诸如"hello"之类的字符串文字时,编译器会在String内部为您创建一个新对象。

没有为StringBuffers 执行这样的事情(尽管 JavaStringBuffer在内部将 s 用于另一个目的 - 用于实现字符串连接)。

有关更多详细信息,请参阅字符串对象和字符串文字之间的区别

其他指针:

于 2012-08-16T11:40:44.990 回答
0

String 是一个可变类,并且具有内置构造函数,可以从字符串文字创建 String 对象。

在 String 的情况下也不例外(就像像原始 .eg int i =0 一样创建它)。String 还执行构造函数来初始化以下(只是它的抽象而不是直接可见的区别):

String str = "ABC";

因为这里的“ABC”也代表一个字符串对象,程序员不能直接使用,但它驻留在字符串池中。并且当这条语句将被执行时,JVM 将在内部调用私有构造函数以使用位于池中的“ABC”对象创建对象。

于 2012-08-16T11:44:47.393 回答
0

基本上,由于字符串被大量使用,Java 提供了一种用于实例化字符串的速记解决方案。

而不是总是使用这个,

String str = new String ("hello");

Java 使它能够做到这一点:

String str = "hello";
于 2014-02-11T15:12:43.713 回答