将字符串与==进行比较,这些字符串在Java中声明为final [英] Comparing strings with == which are declared final in Java
问题描述
我对Java中的字符串有一个简单的问题。以下简单代码段仅连接两个字符串,然后将它们与 ==
进行比较。
I have a simple question about strings in Java. The following segment of simple code just concatenates two strings and then compares them with ==
.
String str1="str";
String str2="ing";
String concat=str1+str2;
System.out.println(concat=="string");
比较表达式 concat ==string
返回 false
显而易见(我理解 equals()
和 == <之间的区别/ code>)。
The comparison expression concat=="string"
returns false
as obvious (I understand the difference between equals()
and ==
).
当这两个字符串被声明为 final
喜欢这样,
When these two strings are declared final
like so,
final String str1="str";
final String str2="ing";
String concat=str1+str2;
System.out.println(concat=="string");
比较表达式 concat ==string
,在这种情况下返回 true
。为什么 final
有所作为?它是否必须对实习池做一些事情或者我只是被误导了?
The comparison expression concat=="string"
, in this case returns true
. Why does final
make a difference? Does it have to do something with the intern pool or I'm just being misled?
推荐答案
当你声明<$ c时$ c> String ( immutable )变量为 final
,并使用编译时常量表达式初始化它,它也成为编译时常量表达式,其值由编译器使用它来内联。因此,在第二个代码示例中,在内联值之后,编译器将字符串连接转换为:
When you declare a String
(which is immutable) variable as final
, and initialize it with a compile-time constant expression, it also becomes a compile-time constant expression, and its value is inlined by the compiler where it is used. So, in your second code example, after inlining the values, the string concatenation is translated by the compiler to:
String concat = "str" + "ing"; // which then becomes `String concat = "string";`
与<$ c相比$ c>string将为您提供 true
,因为字符串文字 interned 。
which when compared to "string"
will give you true
, because string literals are interned.
A原始类型或类型的变量
String
,即final
并使用编译时常量表达式初始化(第15.28节) ,被称为常量变量。
A variable of primitive type or type
String
, that isfinal
and initialized with a compile-time constant expression (§15.28), is called a constant variable.
String
类型的编译时常量表达式总是interned,以便共享唯一的实例,使用方法String #intern()
。
Compile-time constant expressions of type
String
are always "interned" so as to share unique instances, using the methodString#intern()
.
在您的第一个代码示例中并非如此,其中 String
变量不是 final
。因此,它们不是编译时常量表达式。连接操作将延迟到运行时,从而导致创建新的 String
对象。您可以通过比较两个代码的字节代码来验证这一点。
This is not the case in your first code example, where the String
variables are not final
. So, they are not a compile-time constant expressions. The concatenation operation there will be delayed till runtime, thus leading to the creation of a new String
object. You can verify this by comparing byte code of both the codes.
第一个代码示例(非 - final
版本)编译为以下字节代码:
The first code example (non-final
version) is compiled to the following byte code:
Code:
0: ldc #2; //String str
2: astore_1
3: ldc #3; //String ing
5: astore_2
6: new #4; //class java/lang/StringBuilder
9: dup
10: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: ldc #9; //String string
31: if_acmpne 38
34: iconst_1
35: goto 39
38: iconst_0
39: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
42: return
显然它是在两个单独的变量中存储 str
和 ing
,并使用 StringBuilder
执行连接操作。
Clearly it is storing str
and ing
in two separate variables, and using StringBuilder
to perform the concatenation operation.
然而,你的第二个代码示例( final
():
Whereas, your second code example (final
version) looks like this:
Code:
0: ldc #2; //String string
2: astore_3
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_3
7: ldc #2; //String string
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
因此它直接内联最终变量以在编译时创建String string
,该步骤由 ldc
操作加载 0
。然后在步骤 7
中通过 ldc
操作加载第二个字符串文字。它不涉及在运行时创建任何新的 String
对象。 String在编译时已经知道,并且它们被实现。
So it directly inlines the final variable to create String string
at compile time, which is loaded by ldc
operation in step 0
. Then the second string literal is loaded by ldc
operation in step 7
. It doesn't involve creation of any new String
object at runtime. The String is already known at compile time, and they are interned.
这篇关于将字符串与==进行比较,这些字符串在Java中声明为final的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!