【问题标题】:What is need of String s = new String("abc") when we can create String s = "abc"当我们可以创建 String s = "abc" 时,需要什么 String s = new String("abc")
【发布时间】:2015-10-17 08:15:39
【问题描述】:

据我了解

String s = new String("abc") 将创建两个对象-

  1. String 常量池中的一个(如果"abc" 尚未在常量池中)
  2. 堆内存中的一个

尽管对于实际创建的对象数量和位置存在多种理解。

无论如何我有以下问题 -

  1. 为什么 String 类的 java 文档中没有包含关于将创建多少对象以及在哪里创建的内容?
  2. 为什么 new String(String) 在 String 类中提供,但字符串是不可变的?也可以假设由 String s = "abc" 或 String s = new String("abc") 创建的所有字符串都将在字符串常量池中可用?李>
  3. StringBuilder 或StringBuffer 中用于创建或附加的字符串字面量,它们是否也进入字符串常量池或仅保留在堆内存中。

编辑

intern() 方法的 java 文档清楚地谈到了常量池,但是 String(String) 没有这样说的。

【问题讨论】:

  • WRT“需要”:接近0,不记得前几年用过。也许是为了测试没有缺陷的== 比较或其他奇怪的原因,比如想要一个安全的锁对象,它也会打印自己。自动代码分析甚至可能会发出警告。
  • @zapl - 从历史上看,构造函数有一个真正的目的 - 使用较小的 char 数组制作副本。见stackoverflow.com/q/16123446/2158288

标签: java string


【解决方案1】:

为什么 String 类的 java 文档中没有包含关于将创建多少个对象以及在哪里创建的内容?

被Docs of String覆盖

String 类表示字符串。 Java 程序中的所有字符串文字,例如“abc”,都是作为此类的实例实现的。 字符串是常量;它们的值在创建后无法更改。字符串缓冲区支持可变字符串。因为 String 对象是不可变的,所以它们可以被共享。例如:

 String str = "abc";

相当于:

 char data[] = {'a', 'b', 'c'};
 String str = new String(data);

来自Java language specification

String 对象有一个常量(不变的)值。

字符串字面量(第 3.10.5 节)是对 String 类实例的引用。

来自JSL # 3.10.5. String Literals

此外,字符串字面量总是引用 String 类的同一个实例。这是因为字符串字面量 - 或者更一般地说,作为常量表达式值的字符串(第 15.28 节) - 是“内部的”,以便使用 String.intern 方法共享唯一实例。

.

为什么在 String 类中提供 new String(String) 提供的字符串是不可变的?也可以假设所有字符串,由 String s = "abc" 或 String s = new String("abc" ),是否会在字符串常量池中可用?

既然String是对象,那么有效的声明方式是

String s = new String("abc");

但是String s = "abc"; 是出于其他原因而设计的

Java 的设计者决定在面向对象的语言中保留原始类型,而不是让一切都成为对象,以提高语言的性能。

因为它是最有用的类 出于性能原因,Java 的 String 被设计为介于原语和类之间。

在StringBuilder或StringBuffer中用于创建或附加的String字面量,它们是否也进入String常量池或仅保留在堆内存中。

考虑这个例子

StringBuilder sb = new StringBuilder("abc");

常量池中可用的文字"abc" 和堆中创建的对象sb。

试一试我的旧答案:How can a string be initialized using " "?

【讨论】:

  • 投反对票。没有真正回答问题并且是错误的。从 char 数组创建字符串并不等同于使用常量。示例:String a = "x"; String b = "x"; char[] ca = {'x'}; String c = new String(ca); 变量 a 和 b 现在指向同一个对象,但 c 指向不同的对象。此外,Java 字符串是对象。它们不是“介于”原始类型和引用类型之间。是的,您可以使用 + 运算符,但这只是语法糖,与“性能原因”无关。关于“有效声明方式”的东西没有意义。
  • 将尝试回答您的问题: 1)我从未说过它等于 char 数组。所以从你的角度来看,官方 API 文档链接或错误? 2) Java 字符串是对象的。毫无疑问。只是它看起来像一个原始类型的声明和常量池(通过语言优化性能)。 3)but that's just syntactic sugar and has nothing to do with "performance reasons"。我从来没有在我的回答中提到这一点。 4) 与文字样式不同的任何其他对象一样,关于对象声明的有效方式 id。希望清除。
  • 1) 是的,严格来说,官方 API 文档是错误的。文档中的示例旨在说明不变性,在这方面,字符串是等价的,但在其他方面,它们不是。 2)我不明白。 3)我假设你觉得字符串就像原语,因为它们可以是操作数。对不起。 4) 我不明白。
  • @JonaChristopherSahnwaldt 没关系。
【解决方案2】:

String s = new String("abc") 将创建两个对象:

  • 字符串常量池中的一个(如果“abc”尚未在常量池中)

没有。它在常量池中。它是由编译器放在那里的。

  • 堆内存中的一个

正确。

尽管对于实际创建的对象数量和位置存在很多理解。

许多误解:只有一个正确的理解。

为什么 String 类的 java 文档中没有包含关于将创建多少个对象以及在哪里创建的内容?

问题的前提不正确。它被覆盖。不可能是“创建了多少个字符串”的确切形式,但由于这个问题在过去 20 年中已经被问过数百万次,所以答案并不完全是一个秘密。或者不应该。

为什么在 String 类中仍然提供 new String(String) 提供的字符串是不可变的?

所以你可以创建一个新的。

是否也可以假设由 String s = "abc" 或 String s = new String("abc") 创建的所有字符串都将在字符串常量池中可用?

没有。只有字符串文字和String.intern() 的结果在常量池中。这也被记录在案。

在StringBuilder或StringBuffer中用于创建或附加的String字面量,它们是否也进入String常量池或仅保留在堆内存中。

所有字符串字面量都被编译器放入常量池中。

【讨论】:

  • 第一点,No. It is in the constant pool. It was put there by the compiler. 怎么可能编译?根据intern() 方法A pool of strings, initially empty, is maintained privately by the class String. 的java 文档,显然对象创建是运行时和实际JVM 实例中的过程。到你的第 5 点 So you can create a new one. 如果我已经有了不可变的字符串,为什么还要创建一个新字符串?
  • @sarvesh 被编译器放入.class文件的常量池中,所有.class文件的常量池中的字符串字面量被类加载器合并到运行时字符串池中.
  • 这看起来很有说服力。谢谢。
猜你喜欢
  • 2015-11-21
  • 2013-10-20
  • 1970-01-01
  • 2011-09-06
  • 1970-01-01
  • 2014-05-01
  • 2012-03-27
  • 1970-01-01
  • 2010-09-24
相关资源
最近更新 更多