简体   繁体   English

Java:字符串文字和+运算符

[英]Java: String literal and + operator

import java.util.*;
import java.lang.*;
import java.io.*;    

class Test {
   public static void main (String[] args)  {

      String a="hello"+"world";  //line 1
      String b="hello";
      String c="world";
      String d=b+c;
      String e="helloworld";
      System.out.println(e==a);
      System.out.println(a==d);
     }
}

output: 输出:

true

false

From this discussion How does the String class override the + operator? 通过这次讨论,String类如何覆盖+运算符? I understood that 'a' and 'e' will refer to same String literal object. 我知道'a'和'e'将引用相同的String文字对象。

Could anybody please tell 有人能告诉我吗

  1. Why a and d are not referring to same string literal object? 为什么ad没有引用相同的字符串文字对象?

  2. How many objects were creating in line 1 第1行中创建了多少个对象

From JLS 4.3.3. JLS 4.3.3起。 The Class String 类字符串

The string concatenation operator + (§15.18.1) implicitly creates a new String object when the result is not a compile-time constant expression (§15.28). 当结果不是编译时常量表达式(第15.28节)时,字符串串联运算符+ (第15.18.1节)隐式创建一个新的String对象。

Because literal value of a is "helloworld" and literal value of d is a reference object of b + c that is not a literal as from above JLS 4.3.3 . 因为a的字面值是"helloworld" ,而d的字面值是b + c的引用对象,所以它不是JLS 4.3.3以上的字面值。

From JLS 3.10.5 String Literals JLS 3.10.5字符串文字开始

A string literal consists of zero or more characters enclosed in double quotes. 字符串文字包含零个或多个用双引号引起来的字符。

From 15.28. 15.28开始。 Constant Expressions 常数表达式

A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following: 编译时常量表达式是表示原始类型或String的值的表达式,该值不会突然完成,并且仅使用以下内容组成:

  • Literals of primitive type and literals of type String (§3.10.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5) 基本类型的文字和字符串类型的文字(§3.10.1,§3.10.2,§3.10.3,§3.10.4,§3.10.5)

If you want to make System.out.println(a==d); 如果要制作System.out.println(a==d); true use final keyword see below code: 真正使用final关键字,请参见以下代码:

  String a="hello"+"world";  //line 1
  final String b="hello"; // now b is a literal
  final String c="world";// now c is a literal
  String d=b+c;
  String e="helloworld";
  System.out.println(e==a);
  System.out.println(a==d);// now it will be true because both are literals.

Answer for comment: 回答评论:
How many objects were creating in line 1: Answer is 3 在第1行中创建了多少个对象:答案是3
String a="hello"+"world"; 字符串a =“ hello” +“ world”;

1st literal object hello 第一个文字对象hello
2nd literal object world 第二文字对象world
3rd literal object "hello"+"world" == "helloworld" 第三文字对象"hello"+"world" == "helloworld"

The == sign checks if references to variables are the same. ==符号检查对变量的引用是否相同。 To check if any object is equal to other use Object.equals(Object o) method like this: 要检查是否有任何对象与其他对象相等,请使用Object.equals(Object o)方法,如下所示:

e.equals(a);

The == operator checks reference equality, not object equality. ==运算符检查引用相等性,而不检查对象相等性。 In your example two String instances with content "helloworld" have been created. 在您的示例中,创建了两个内容为"helloworld" String实例。 The variables a and e refer to the same instance (see below), while a and d do not. 变量ae指向同一个实例(见下文),而ad没有。 String equality can be checked with the equals() method, that is a.equals(d) is true. 可以使用equals()方法检查字符串是否相等,即a.equals(d)为true。

The reason that a and e refer to the same instance is that String constants are interned. ae引用同一实例的原因是String常量是内在的。 Every time a string constant, like "helloworld" , is encountered, it is checked if such a constant was already encountered, and if it has, the old String instance is returned instead of creating a new one. 每次遇到一个字符串常量(例如"helloworld" )时,都会检查是否已遇到这样的常量,如果已经遇到,则将返回旧的String实例,而不是创建一个新的实例。 Although "hello" + "world" does not look like a String constant, it is optimized to a String constant by the Java compiler, and therefore it is interned like e , which is why a == e is true. 尽管"hello" + "world"看起来不像String常量,但是Java编译器已将其优化为String常量,因此它像e一样被内插,这就是a == e为true的原因。 In constrast, b + c is not optimized to a constant, which is why a == d is false (however, a.equals(d) would be true). 相反, b + c没有优化为常数,这就是为什么a == d为假(但是a.equals(d)为真)的原因。

1) It's because String objects are immutable. 1)这是因为String对象是不可变的。 Once you create a String object and assign it a value, it has the same value forever that cannot be changed. 一旦创建了String对象并为其分配了一个值,它就永远具有无法更改的相同值。 Thus there is always created a new String object when you make any operations with it (for example joining). 因此,当您对它进行任何操作(例如,联接)时,总会创建一个新的String对象。

In heap there is a special part of it that serves as a pool for String constants. 在堆中,有一个特殊的部分用作String常量的池。 If the compiler encounters a String literal, it first looks into this part of memory whether identical object ( String ) already exists. 如果编译器遇到String文字,则它首先检查内存的这一部分是否已经存在相同的对象( String )。 If it does, it assigns a reference to this already existing object ( String ) instead of creating a new one. 如果是这样,它将为这个已经存在的对象( String )分配一个引用,而不是创建一个新的引用。 (This is the reason why String s are immutable, so no one can change it. Because if several references would point to this String and one of them would change its value, it would create a mess.) (这就是String不可变的原因,因此没有人可以更改它。因为如果多个引用指向此String,而其中一个引用将更改其值,则会造成混乱。)

Now let's take a look what is going on in this code snippet and try to find the answer to both of your questions at once. 现在,让我们看一下此代码段中的情况,并尝试一次找到两个问题的答案。

(1) String a="hello"+"world";  //line 1
(2) String b="hello"; // now b is a literal
(3) String c="world";
(4) String d=b+c;
(5) String e="helloworld";
(6) System.out.println(e==a);
(7) System.out.println(a==d);

(1) First there is created a reference value a that points to type String. (1)首先,创建一个指向String类型的参考值a Then there is created literal "hello" in this special pool in heap mentioned earlier (1st String object). 然后,在前面提到的堆中的这个特殊池中创建了文字“ hello”(第一个String对象)。 Then there is created literal "world" in the pool (2nd String object). 然后在池中创建文字“世界”(第二个String对象)。 Then, since Strings are immutable, there is created another literal in this pool- "helloworld" and it is assigned to this reference variable a (3rd String object - this is the answer to your question Nr. 2). 然后,由于字符串是不可变的,因此在该池中创建了另一个文字-“ helloworld”,并将其分配给此引用变量a (第三个字符串对象-这是对问题2的回答)。

(2) Literals "hello" and "world" created in (1) were created in pool and weren't assigned to any reference value, but they stil exist in this pool. (2)在(1)中创建的文字“ hello”和“ world”是在池中创建的,没有分配任何参考值,但它们仍然存在于该池中。 In this line there is reference variable of type String b created and it is assigned to this literal "hello" existing in pool. 在此行中,创建了类型为String b的引用变量,并将其分配给池中存在的此文字“ hello”。

(3) same as (2) (3)与(2)相同

(4) Created reference value of type String d . (4)创建类型为String d的参考值。 Although there already IS a String literal in this special heap part (pool) with value "helloworld", a new String object with value "helloworld" is created in heap - that means in non-pool part of heap. 尽管在这个特殊的堆部分(池)中已经有一个字符串文字,其值为“ helloworld”,但是在堆中创建了一个值为“ helloworld”的新String对象 -这意味着在堆的非池部分。 Therefore you have two different objects of type String with value "helloworld" (One in a pool and the other in a non-pool part of heap). 因此,您有两个不同的String类型的对象,其值均为“ helloworld”(一个在池中,另一个在堆的非池部分中)。 If you now compare with == operator reference values a and d , both of them point to different objects (with same value though, so method equals would return true). 如果现在与==运算符参考值ad进行比较,它们都指向不同的对象(尽管具有相同的值,所以方法equals将返回true)。

(5) Created reference value e of type String. (5)创建字符串类型的参考值e In pool part of heap there already is a String "helloworld" (we created it in (1) and pointed it to reference variable a ) so the reference variable e is assigned to this object. 在堆的池部分中,已经有一个字符串“ helloworld”(我们在(1)中创建了它,并将其指向引用变量a ),因此将引用变量e分配给了此对象。 And points to same place as a . 并指向同一个地方 Therefore if you compare references a == e you get true. 因此,如果您比较引用a == e,则为true。 The same would be for method equals 方法等于

(6) and (7) were explained in previous points (6)和(7)在前面的几点中进行了解释

TLDR: TLDR:

1) because it is not the same object 1)因为它不是同一对象

2) 3 2)3

The == operator checks if the two objects refer to the same place in memory. ==运算符检查两个对象是否引用内存中的相同位置。

The a = "hello" + "world;" a = "hello" + "world;" evaluates to the literal "helloworld" and e="helloworld" is given. 计算为文字"helloworld"并给出e="helloworld" They refer to the same memory location. 它们引用相同的存储位置。 Hence the expression e==a evaluates to true. 因此,表达式e==a计算为true。

The expression d=b+c also evaluates to "helloworld" but this result is stored at a different location. 表达式d=b+c计算结果也为"helloworld"但此结果存储在其他位置。 It does not refer to the same object. 它没有引用相同的对象。 Hence the expression a==d evaluates to false. 因此,表达式a==d计算结果为false。

Using a.equals(d) will output true because equals() checks the contents of the 2 objects. 使用a.equals(d)将输出true,因为equals()检查2个对象的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM