Java 是否优化运行时字符串的创建?

发布于 2024-11-13 22:47:49 字数 633 浏览 1 评论 0原文

假设我在运行时创建了以下两个字符串(例如,根据用户输入):

public void someMethod(String input) {

   if ( input == null ) return;

   String a = input + input;
   String b = input;

   ...

}

Java(及其编译器)是否足够智能,可以在运行时检测到 b 包含在 a 因此不需要为b分配内存? b 可以只指向一半长度的 a 吗?

换句话说,Java 是否实现了 String.intern() 的动态版本?

编辑

考虑到到目前为止所做的答案,我的例子应该是:

public void someMethod(String input) {

   if ( input == null ) return;

   String a = input + input + input;
   String b = input + input;

   ...

}

Let's assume I create the following two strings at runtime (from user input for example):

public void someMethod(String input) {

   if ( input == null ) return;

   String a = input + input;
   String b = input;

   ...

}

Is Java (and its compiler) smart enough to detect at runtime that b is contained in a and therefore it is not necessary to allocate memory for b? b could just point at a with half the length?

In other words, does Java implement a dynamic version of String.intern()?

EDIT

Considering answers made so far, my example should be:

public void someMethod(String input) {

   if ( input == null ) return;

   String a = input + input + input;
   String b = input + input;

   ...

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

宣告ˉ结束 2024-11-20 22:47:49

您实际上并没有在示例中创建两个字符串:b 只是对 input 的引用。因此,为了完成您所要求的操作,Java 必须在创建新字符串时以某种方式返回并更改旧字符串(例如通过说 input + input)。

为了回答您更广泛的问题,据我所知,两个字符串共享内存的唯一方法(此外,正如您提到的,是 intern()'d)是使用 substring()。因此,如果您确实想节省内存,可以这样做:(

String a = input + input;
String b = a.substring(input.length());

要明确的是,只有当 b 的值存储在 input 之外的其他位置时,这才会节省内存。被丢弃并最终被垃圾收集。)

编辑

新的和改进的问题的新的和改进的示例:(

String a = input + input + input;
String b = a.substring(2 * input.length());

请注意,这总是比问题中的第二个示例节省内存,因为我们完全避免了分配,所以前面的警告。不适用。)

You're not actually creating two strings in your example: b is just a reference to input. So, to do what you're asking, Java would have to somehow go back and alter old strings when a new string is created (such as by saying input + input).

To answer your broader question, AFAIK the only way for two strings to be sharing memory (besides, as you mention, being intern()'d) is for one or both to have been created using substring(). So if you really wanted to save on memory, you could do this:

String a = input + input;
String b = a.substring(input.length());

(To be clear, this will only save memory if the value of b is being stored somewhere but input is discarded and winds up garbage-collected.)

EDIT

New and improved example for new and improved question:

String a = input + input + input;
String b = a.substring(2 * input.length());

(Note that this will always save memory over the second example in the question, since we've avoided an allocation altogether. So the previous caveat doesn't apply.)

回眸一笑 2024-11-20 22:47:49

不,这不会发生,因为作为参数传入的字符串已经存在,并且字符串是不可变的。双倍长度的数组必须单独创建,因为原始数组没有空间容纳更多字符。

但在相反的情况下,您从长字符串开始,然后使用 substring() 创建一个较短的字符串,这两个字符串实际上将共享相同的 char 数组。

No, this won't happen, because the String passed in as an argument already exists, and Strings are immutable. The double-length one has to be created separately, since the original array won't have room for more characters.

In the reverse case, though -- where you start out with the long string, and use substring() to create a shorter one -- the two strings will, indeed, share the same char array.

梦中楼上月下 2024-11-20 22:47:49

正如其他人指出的那样,b 只是指向与 input 相同的字符串。

至于a,我们可以使用javap 反汇编代码:

public static void someMethod(java.lang.String);
  Code:
   0:   aload_0
   1:   ifnonnull   5
   4:   return
   5:   new #4; //class java/lang/StringBuilder
   8:   dup
   9:   invokespecial   #5; //Method java/lang/StringBuilder."<init>":()V
   12:  aload_0
   13:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   16:  aload_0
   17:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   20:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   23:  astore_1
   24:  aload_0
   25:  astore_2
   26:  return

编译器使用 StringBuilder.append() 执行串联,(至少在 Sun/OpenJDK 中)只是将所有内容复制到一个大的 中char 数组 - 这里没有 intern()ing。这同样适用于您的编辑 - 输入字符串总共被附加 5 次。

我可以想象可以编写 String(Builder|Buffer) 的替代实现来维护数组链,这在某些情况下可以实现更好的重用和效率。

As others have pointed out, b just points to the same string as input.

As for a, we can use javap to disassemble your code:

public static void someMethod(java.lang.String);
  Code:
   0:   aload_0
   1:   ifnonnull   5
   4:   return
   5:   new #4; //class java/lang/StringBuilder
   8:   dup
   9:   invokespecial   #5; //Method java/lang/StringBuilder."<init>":()V
   12:  aload_0
   13:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   16:  aload_0
   17:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   20:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   23:  astore_1
   24:  aload_0
   25:  astore_2
   26:  return

The compiler uses StringBuilder.append() to perform the concatenation, which (in Sun/OpenJDK, at least) just copies everything into a big char array - no intern()ing here. Same applies with your edit - the input string is appended 5 times in total.

I can imagine an alternate implementation of String(Builder|Buffer) could be written to maintain a chain of arrays, which would allow better reuse and efficiency in some cases.

爱给你人给你 2024-11-20 22:47:49

不,编译器足够智能,可以在编译时检测字符串连接,例如:

       String a = "hello, " + "world";
       //Will become
       String a = "hello, world";

但是每次创建字符串时,子字符串匹配的工作量有点大。
然而,Java 试图避免创建多个字符串(如果两个字符串相等),您应该检查 String.intern()

Nop, the compiler is intelligent enough to detect String concatenation at compile time, for instance:

       String a = "hello, " + "world";
       //Will become
       String a = "hello, world";

But substring matching is a bit much to do every time you create a string.
However Java tries to avoid multiple string creation (if two strings are equal), you should check String.intern()

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文