当前位置: 首页 > 知识库问答 >
问题:

将字符串与在Java中声明为final的==进行比较

海翼
2023-03-14

我有一个关于Java中字符串的简单问题。下面的简单代码段只是将两个字符串连接起来,然后将它们与==进行比较。

String str1="str";
String str2="ing";
String concat=str1+str2;

System.out.println(concat=="string");

比较表达式concat==“string”返回false非常明显(我理解equals()==之间的区别)。

当这两个字符串声明为final时,

final String str1="str";
final String str2="ing";
String concat=str1+str2;

System.out.println(concat=="string");

比较表达式concat==“string”在本例中返回true。为什么final会起作用?是不是一定要用实习生的钱呢?还是我被误导了?

共有1个答案

冉绯辞
2023-03-14

当您将string(它是不可变的)变量声明为final并使用编译时常量表达式对其进行初始化时,它也会成为编译时常量表达式,其值由使用它的编译器内联。因此,在第二个代码示例中,在内联值之后,编译器将字符串级联转换为:

String concat = "str" + "ing";  // which then becomes `String concat = "string";`

当与“string”相比较时,它将给出true,因为字符串文字是内部的。

来自JLS§4.12.4-final变量:

基元类型或string类型的变量,即final并用编译时常量表达式(§15.28)初始化的变量,称为常量变量。

也来自JLS§15.28-常数表达式:

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

在您的第一个代码示例中情况并非如此,其中string变量不是final。因此,它们不是编译时常量表达式。那里的串联操作将延迟到运行时,从而导致创建一个新的string对象。您可以通过比较两个代码的字节代码来验证这一点。

第一个代码示例(非final版本)被编译为以下字节码:

  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

显然,它将string存储在两个单独的变量中,并使用StringBuilder执行级联操作。

  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

因此它直接内联final变量以在编译时创建字符串String,该字符串由步骤0中的LDC操作加载。然后通过步骤7中的LDC操作加载第二个字符串文字。它不涉及在运行时创建任何新的string对象。该字符串在编译时已知,并且它们被存储。

 类似资料:
  • 问题内容: 我有一个关于Java字符串的简单问题。以下简单代码段仅连接两个字符串,然后将它们与进行比较。 比较表达式concat==”string”返回false那么明显(I明白之间的差值equals()和==)。 当这样声明这两个字符串时final, 比较表达式在这种情况下返回。为什么有所作为?它与实习生池有关系吗,还是我被误导了? 问题答案: 当你将(是不可变的)变量声明为,并使用编译时常量表

  • 问题内容: 有人可以澄清以下代码的重要性吗? 对象A被声明为final,但是我可以更改该对象的实例变量的值,也可以获取更新后的值。那么将对象声明为final的意义何在?我知道将原始数据类型声明为final,这使该变量保持不变。 问题答案: ob将无法引用任何其他对象:final关键字。 不能重新分配。但是您可以更改其内部(如果它是原始的,则是可变的)。所以这有效: 但这不是:

  • 问题内容: 这些声明和和之间有什么区别? 问题答案: 总是在堆上创建一个新对象 使用字符串池 试试这个小例子: 为避免在堆上创建不必要的对象,请使用第二种形式。

  • 问题内容: 当我得知该类在Java中被声明为final时,我想知道为什么会这样。那时我没有找到任何答案,但是这篇文章:如何在Java中创建String类的副本?让我想起了我的疑问。 当然,String提供了我所需要的所有功能,而且我从未想过需要扩展String类的任何操作,但是您仍然永远不会知道有人可能需要什么! 那么,有谁知道设计师决定将其定稿时的意图是什么? 问题答案: 将字符串实现为不可变对

  • 我对OffsetDateTime的用法非常陌生,我正在尝试将OffsetDateTime字符串与OffsetDateTime进行比较。以这种方式在java中使用now(), 但我正在学习java。时间总体安排所有3种情况下的DateTimeParseException。 然而,如果我将2个OffsetDateTime字符串与CompareTo方法进行比较,它的工作就很好了。 有没有人能在这方面给我

  • 问题内容: 我有一个美国所有州的枚举列表,如下所示: 在测试文件中,我将从包含状态的文本文件中读取输入。由于它们是字符串,因此如何将其与枚举列表的值进行比较,以便将值分配给我设置为的变量: 我了解我需要浏览枚举列表。但是,由于值不是字符串类型,如何比较?这就是我盲目输入的内容。我不知道这是否正确。 问题答案: 试试这个 您可能要处理IllegalArgumentException,如果“ s”值与