将字符串与==进行比较,这些字符串在Java中声明为final [英] Comparing strings with == which are declared final in Java

查看:157
本文介绍了将字符串与==进行比较,这些字符串在Java中声明为final的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对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.

来自 JLS§ 4.12.4 - final 变量


A原始类型或类型的变量 String ,即 final 并使用编译时常量表达式初始化(​​第15.28节) ,被称为常量变量

A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.

同样来自JLS§ 15.28 - 常量表达式:


String 类型的编译时常量表达式总是interned,以便共享唯一的实例,使用方法 String #intern()

Compile-time constant expressions of type String are always "interned" so as to share unique instances, using the method String#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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆