【问题标题】:where do actual parameters in java store [duplicate]java中的实际参数在哪里存储[重复]
【发布时间】:2014-02-10 11:37:57
【问题描述】:

如果我将 String 文字传递给某些方法:

String s=new String("stack");
String s2=s.concat("overflow");

字符串“溢出”的存储位置。

我的一个朋友争辩说它是在String 常量池中创建的,我反对他。

请告诉我

提前致谢。

【问题讨论】:

  • 你为什么反对他?这是一个字符串常量。
  • 这个问题的“字符串在哪里创建”和“参数在哪里存储”方面大多有不同的答案。参数传递机制对字符串和其他对象的操作相同,但取决于 JVM,字符串字面量可能会或可能不会以特殊方式分配。

标签: java string memory


【解决方案1】:

所有String 文字都进入常量池。结束。在这种情况下,两个常量 "stack""overflow" 进入池中。创建一个新的String,它与池中的"stack" 具有相同的值,然后通过将常量池中的"overflow" 连接到它来创建另一个String

摘自javap -c -verbose Test

Constant pool:
   #1 = Methodref          #10.#19        //  java/lang/Object."<init>":()V
   #2 = Class              #20            //  java/lang/String
   #3 = String             #21            //  stack
   #4 = Methodref          #2.#22         //  java/lang/String."<init>":(Ljava/lang/String;)V
   #5 = String             #23            //  overflow
   #6 = Methodref          #2.#24         //  java/lang/String.concat:(Ljava/lang/String;)Ljava/lang/String;

【讨论】:

  • JLS 的相关部分:docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5 - “此外,字符串文字总是引用 String 类的同一个实例。这是因为字符串文字 - 或者更一般地说,字符串是值常量表达式(第 15.28 节) - 被“实习”,以便使用 String.intern 方法共享唯一实例。”
  • @davmac 我实际上编译了这段代码,因为我不确定这是否是编译时常量(“stack”+“overflow”是),而且它比挖掘 JLS 更容易.
  • 没关系。我已经赞成你的回答。我添加了 JLS 参考作为评论,所以如果有人想要它就在那里。
  • @davmac 总是很高兴得到引用。只是没有足够的动力自己现在提供它。 ;-)
【解决方案2】:

这个问题肯定是不确定的,但是你可以找出java编译器和JVM的某种组合是如何做到的。

据我所知,没有什么能阻止编写一个 java 编译器,当它看到一个字符串常量时,会发出字节码以某种方式在堆中创建该字符串 只要因为 JLS 中关于字符串文字的规则仍然保持不变。例如,String.intern 可以维护一个全局 Map,编译器可以编译如下字符串字面量:

create a char array of the desired size
put character at index 0
put character at index 1
...
put character at index (length-1)
construct the actual string object
pass the String just created to String.intern and leave result on the stack

实际上,可以有一个预处理器将所有字符串常量更改为

(extra.HeapString.createString(new char[] { ... }))

并让createString 创建一个String 实例,使其符合String 文字的规则。而且你不能编写一个程序来检测它是从原始源代码还是从预处理的源代码编译的(除了通过extra.HeapString 的反射)。

【讨论】:

  • 反对字符串池和堆是误导:字符串池可能存储在主堆上(例如从 Java 7 开始的热点就是这种情况)。
  • 此行为在 JLS 中明确指定。你可以编写一个以各种方式破坏规则的编译器,但它不会是一个正确的 Java 编译器。
  • @chrylis 这就是我的意思。
  • @chrylis 版本?段落?页面?
  • @Ingo 你的论点有缺陷。字符串文字是否在堆上生成对象不影响问题的答案(关于字符串文字是否在“字符串常量池”中)。要求对字符串文字进行实习(JLS 3.10.5)的效果是存在一个字符串常量池,并且 JLS 要求字符串文字从该池中产生字符串。
【解决方案3】:

字符串stack将在堆中,字符串overflow在常量池中,第三个字符串作为连接的结果stackoverflow在常量池中。

【讨论】:

  • 大部分是错误的,正确的,错误的。 stack 在常量池中,overflow 在常量池中,stackoverflow 在堆上。根据 JVM 作者的判断,常量池可能位于堆上。 stackoverflow 不会进入池,除非它被明确地实习。
  • "stack" 文字将在常量池中,但 s 将引用它的副本,该副本将在堆上(由于new String(...))。
猜你喜欢
  • 2020-11-08
  • 2018-11-07
  • 1970-01-01
  • 1970-01-01
  • 2016-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多