我正在为J2ME设备编写应用程序,并且非常关心不必要的字符串创建。 由于使用Strings是内置的,即没有必要明确地创建它们,我不确定我是否理解它。
例如,返回一个String(只是使用双引号)会在返回时创建字符串,即如果我有几个返回语句返回不同的字符串,则只会创建一个字符串。是吗?
当使用字符串打印带有异常的消息时,如果没有抛出异常,这些字符串永远不会被创建,对吗?
很抱歉打扰这个新手问题。
答案 0 :(得分:4)
到目前为止,我对你收到的答案一点也不确定。如果你只是返回一个字符串文字,例如
return "foo";
然后将这些值嵌入到类文件中。 JVM确保只创建该字符串的一个实例(来自文字) - 但我不认为它不会保证它不会为所有类中的常量创建字符串当班级本身被加载时。
然后再次,因为字符串只会被创建一次(每个字符串常量),这不太可能是一个问题。
现在,如果您的代码实际上更像是这样:
return "foo" + new Date();
然后 动态创建一个字符串 - 但只有在实际命中了return语句时才会创建它。
答案 1 :(得分:2)
答案比其他一些答案复杂得多。
在加载类时,会创建一次与源代码中的字符串文字对应的String值。此外,这些字符串会自动“实现”,这意味着如果同一个字面值出现在任何类中的多个 中,则只保留一个字符串副本。 (任何其他副本,如果它们被创建将被垃圾收集。)
当应用程序调用{{1}}时,它在评估字符串连接表达式(即new String(...)
运算符)时,或者当它调用在引擎盖下创建字符串的众多库方法之一时,将创建一个新的String。
所以回答你的问题:
1 - 以下实际上根本不会创建一个String。相反,它将返回在加载类时创建的String:
+
2 - 以下将创建两个字符串。首先它将调用someObject.toString(),然后它将与文字连接以提供另一个String。
return "some string";
3 - 以下内容不会创建字符串;见1.
return "The answer is :" + someObject;
4 - 以下将在执行时创建两个字符串;见2.
throw new Exception("Some message");
(实际上,3和4表明创建异常会导致捕获当前线程的调用堆栈的详细信息,并且这些细节包括每个帧的方法名称,类名和文件名。未指定当代表这些东西的字符串实际上被创建,或者它们是否被实现时。所以可能创建异常对象的行为会触发创建多个字符串。)
答案 2 :(得分:1)
答案 3 :(得分:1)
<击>是。如果通过调用构造函数创建实例的表达式或者不执行(对于字符串)评估文字的表达式,则不会创建任何内容。
而且,编译器会进行一些优化。基于字符串文字的字符串对象将只创建一次并在之后实现。像这里:
public String getHello() {
return "Hello";
}
public void test() {
String s = getHello(); // String object created
String t = getHello(); // no new String object created
}
击> <击> 撞击>
JVMS有不同的“意见”:
在以下情况下可能会隐式创建新的类实例:
- 加载包含String文字的类或接口可能会创建一个新的String对象(第2.4.8节)来表示该文字。如果已经创建了一个String对象来表示该文字的上一次出现,或者如果已经在表示与文字相同的字符串的String对象上调用了String.intern方法,则可能不会发生这种情况。
所以上面的例子是不正确的(我每天都在学习新东西)。 VM在类加载期间检查是否必须创建"Hello"
(并且如果尚不存在则将创建String实例)。
所以现在我的理解是,VM为每个唯一的String文字(在字节代码级别上)创建一个String实例,无论是否使用它。
( on byte code level ,因为编译器可以优化String文字与一个文字的连接,例如:表达式"one"+"two"
将被编译为"onetwo"
)
答案 4 :(得分:0)
只有在调用时才会创建字符串(和其他对象)。
所以回答你的问题:
答案 5 :(得分:0)
这里的主要概念是,在您的逻辑流使解释器执行该行编译代码之前,任何String的堆分配(您所说的创建)或任何对象的更一般术语都不会发生。