我有一个关于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
会起作用?是不是一定要用实习生的钱呢?还是我被误导了?
当您将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
显然,它将str
和ing
存储在两个单独的变量中,并使用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”值与