So sánh chuỗi tiếng Việt trong Java

Sự khác biệt giữa hai tuyên bố sau đây là gì? String s = "text";String s = new String["text"];

new String["text"]; rõ ràng tạo ra một thể hiện mới và khác biệt của một Stringđối tượng; String s = "text";có thể sử dụng lại một thể hiện từ nhóm hằng số chuỗi nếu có sẵn.

Bạn rất hiếm khi muốn sử dụng hàm new String[anotherString]tạo. Từ API:

String[String original]: Khởi tạo một đối tượng mới được tạo String để nó thể hiện cùng một chuỗi các ký tự như đối số; nói cách khác, chuỗi mới được tạo là một bản sao của chuỗi đối số. Trừ khi cần một bản sao rõ ràng của bản gốc, việc sử dụng hàm tạo này là không cần thiết vì các chuỗi là bất biến.

Câu hỏi liên quan

  • Chuỗi Java: Chuỗi String s = new String [Tiếng cười ngớ ngẩn];
  • Chuỗi là các đối tượng trong Java, vậy tại sao chúng ta không sử dụng 'mới' để tạo chúng?

Phân biệt tham chiếu có nghĩa là gì

Kiểm tra đoạn mã sau:     String s1 = "foobar";    String s2 = "foobar";    System.out.println[s1 == s2];      // true    s2 = new String["foobar"];    System.out.println[s1 == s2];      // false    System.out.println[s1.equals[s2]]; // true

==trên hai loại tham chiếu là một so sánh danh tính tham chiếu. Hai đối tượng equalskhông nhất thiết phải có ==. Nó thường sai khi sử dụng ==trên các loại tham chiếu; hầu hết thời gian equalscần phải được sử dụng thay thế.

Tuy nhiên, nếu vì bất kỳ lý do gì bạn cần tạo hai equalsnhưng không phải ==chuỗi, bạn có thể sử dụng hàm new String[anotherString]tạo. Tuy nhiên, cần phải nói lại rằng điều này rất đặc biệt và hiếm khi có ý định.

Người giới thiệu

  • JLS 15,21.3 Toán tử bình đẳng tham chiếu == và! =
  • class Object - boolean Object[equals]

Các vấn đề liên quan

  • Java String.equals so với ==
  • Làm cách nào để so sánh các chuỗi trong Java?

Chuỗi ký tự sẽ đi vào Chuỗi liên tục Pool .

Ảnh chụp nhanh dưới đây có thể giúp bạn hiểu nó một cách trực quan để ghi nhớ nó lâu hơn.

Dòng tạo đối tượng theo dòng: String str1 = new String["java5"];

Sử dụng chuỗi ký tự "java5" trong hàm tạo, một giá trị chuỗi mới được lưu trữ trong nhóm hằng chuỗi. Sử dụng toán tử mới, một đối tượng chuỗi mới được tạo trong heap với giá trị "java5". String str2 = "java5"

Tham chiếu "str2" được chỉ đến giá trị đã được lưu trữ trong nhóm hằng số chuỗi String str3 = new String[str2];

Một đối tượng chuỗi mới được tạo trong heap với cùng giá trị như tham chiếu bởi "str2" String str4 = "java5";

Tham chiếu "str4" được chỉ đến giá trị đã được lưu trữ trong nhóm hằng số chuỗi

Tổng số đối tượng: Heap - 2, Pool - 1

Đọc thêm về cộng đồng Oracle

Người ta tạo một chuỗi trong chuỗi hằng số chuỗi String s = "text";

một chuỗi khác tạo một chuỗi trong nhóm hằng số [ "text"] và một chuỗi khác trong không gian heap bình thường [ s]. Cả hai chuỗi sẽ có cùng một giá trị, đó là "văn bản". String s = new String["text"];

s sau đó bị mất [đủ điều kiện cho GC] nếu sau đó không được sử dụng.

Mặt khác, chuỗi ký tự được sử dụng lại. Nếu bạn sử dụng "text"ở nhiều nơi trong lớp thì thực tế nó sẽ là một và chỉ một Chuỗi [tức là nhiều tham chiếu đến cùng một chuỗi trong nhóm].

JLS

Khái niệm này được gọi là "thực tập" bởi JLS.

Đoạn văn có liên quan từ JLS 7 3.10.5 :

Hơn nữa, một chuỗi ký tự luôn luôn đề cập đến cùng một thể hiện của Chuỗi lớp. Điều này là do các chuỗi ký tự - hay nói chung hơn là các chuỗi là các giá trị của biểu thức hằng [§15.28] - được "thực hiện" để chia sẻ các thể hiện duy nhất, sử dụng phương thức String.i INTERN.
Ví dụ 3.10.5-1. Chuỗi ký tự
Chương trình bao gồm đơn vị biên dịch [§7.3]: package testPackage;class Test {    public static void main[String[] args] {        String hello = "Hello", lo = "lo";        System.out.print[[hello == "Hello"] + " "];        System.out.print[[Other.hello == hello] + " "];        System.out.print[[other.Other.hello == hello] + " "];        System.out.print[[hello == ["Hel"+"lo"]] + " "];        System.out.print[[hello == ["Hel"+lo]] + " "];        System.out.println[hello == ["Hel"+lo].intern[]];    }}class Other { static String hello = "Hello"; }
và đơn vị biên dịch:package other;public class Other { public static String hello = "Hello"; }
tạo ra đầu ra:true true true true false true

Liên doanh

JVMS 7 5.1 nói :

Một chuỗi ký tự là một tham chiếu đến một thể hiện của Chuỗi lớp và được lấy từ cấu trúc CONSTANT_String_info [§4.4.3] trong biểu diễn nhị phân của một lớp hoặc giao diện. Cấu trúc CONSTANT_String_info đưa ra chuỗi các điểm mã Unicode cấu thành chuỗi ký tự.
Ngôn ngữ lập trình Java yêu cầu các chuỗi ký tự chuỗi giống hệt nhau [nghĩa là các chữ có chứa cùng một chuỗi các điểm mã] phải tham chiếu đến cùng một thể hiện của Chuỗi lớp [JLS §3.10.5]. Ngoài ra, nếu phương thức String.i INTERN được gọi trên bất kỳ chuỗi nào, kết quả là một tham chiếu đến cùng thể hiện của lớp sẽ được trả về nếu chuỗi đó xuất hiện dưới dạng một chữ. Do đó, biểu thức sau phải có giá trị đúng:["a" + "b" + "c"].intern[] == "abc"
Để lấy được một chuỗi ký tự, Máy ảo Java kiểm tra chuỗi các điểm mã được đưa ra bởi cấu trúc CONSTANT_String_info.
  • Nếu phương thức String.i INTERN trước đây đã được gọi trong một thể hiện của Chuỗi lớp có chứa một chuỗi các điểm mã Unicode giống hệt với cấu trúc CONSTANT_String_info, thì kết quả của dẫn xuất chuỗi ký tự là một tham chiếu đến cùng thể hiện của Chuỗi lớp.
  • Mặt khác, một thể hiện mới của Chuỗi lớp được tạo có chứa chuỗi các điểm mã Unicode được cung cấp bởi cấu trúc CONSTANT_String_info; một tham chiếu đến thể hiện của lớp đó là kết quả của đạo hàm chuỗi. Cuối cùng, phương thức intern của thể hiện String mới được gọi.

Mã byte

Nó cũng được khuyến khích để xem việc triển khai mã byte trên OpenJDK 7.

Nếu chúng ta dịch ngược: public class StringPool {    public static void main[String[] args] {        String a = "abc";        String b = "abc";        String c = new String["abc"];        System.out.println[a];        System.out.println[b];        System.out.println[a == c];    }}

chúng tôi có trên nhóm liên tục: #2 = String             #32   // abc[...]#32 = Utf8               abc

và main:  0: ldc           #2          // String abc 2: astore_1 3: ldc           #2          // String abc 5: astore_2 6: new           #3          // class java/lang/String 9: dup 10: ldc           #2          // String abc12: invokespecial #4          // Method java/lang/String."":[Ljava/lang/String;]V15: astore_3 16: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;19: aload_1 20: invokevirtual #6          // Method java/io/PrintStream.println:[Ljava/lang/String;]V23: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;26: aload_2 27: invokevirtual #6          // Method java/io/PrintStream.println:[Ljava/lang/String;]V30: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;33: aload_1 34: aload_3 35: if_acmpne     4238: iconst_1 39: goto          4342: iconst_0 43: invokevirtual #7          // Method java/io/PrintStream.println:[Z]V

Lưu ý cách làm:

  • 0và 3: ldc #2hằng số tương tự được tải [bằng chữ]
  • 12: một phiên bản chuỗi mới được tạo [với #2đối số]
  • 35: avà cđược so sánh như các đối tượng thông thường vớiif_acmpne

Việc biểu diễn các chuỗi không đổi là khá kỳ diệu trên mã byte:

  • nó có cấu trúc CONSTANT_String_info chuyên dụng , không giống như các đối tượng thông thường [ví dụ new String]
  • cấu trúc trỏ đến Cấu trúc CONSTANT_Utf8_info có chứa dữ liệu. Đó là dữ liệu cần thiết duy nhất để đại diện cho chuỗi.

và trích dẫn của JVMS ở trên dường như nói rằng bất cứ khi nào Utf8 được chỉ ra là giống nhau, thì các thể hiện giống hệt nhau được tải bởi ldc.

Tôi đã thực hiện các bài kiểm tra tương tự cho các trường và:

  • static final String s = "abc"trỏ đến bảng hằng số thông qua Thuộc tính ConstantValue
  • các trường không phải là cuối cùng không có thuộc tính đó, nhưng vẫn có thể được khởi tạo với ldc

Kết luận : có hỗ trợ mã byte trực tiếp cho nhóm chuỗi và biểu diễn bộ nhớ là hiệu quả.

Phần thưởng: so sánh với nhóm Số nguyên , không có hỗ trợ mã byte trực tiếp [nghĩa là không có tín hiệu CONSTANT_String_infotương tự].

@Braj: tôi nghĩ bạn đã đề cập đến cách khác. Xin hãy sửa tôi nếu tôi sai

Dòng tạo đối tượng theo dòng:

Chuỗi str1 = Chuỗi mới ["java5"]       Pool- "java5" [1 Object] Heap - str1 => "java5" [1 Object]

Chuỗi str2 = "java5"   pool- str2 => "java5" [1 Object] heap - str1 => "java5" [1 Object]

Chuỗi str3 = Chuỗi mới [str2]   pool- str2 => "java5" [1 Object] heap- str1 => "java5", str3 => "java5" [2 Objects]

Chuỗi str4 = "java5"   pool - str2 => str4 => "java5" [1 Object] heap - str1 => "java5", str3 => "java5" [2 Objects]

Hãy nghĩ về "bla"việc trở thành một nhà máy ma thuật như Strings.createString["bla"][giả]. Nhà máy giữ một nhóm tất cả các chuỗi được tạo theo cách này.

Nếu nó được gọi, nó sẽ kiểm tra xem đã có chuỗi trong nhóm có giá trị này chưa. Nếu đúng, nó trả về đối tượng chuỗi này, do đó các chuỗi thu được theo cách này thực sự là cùng một đối tượng.

Nếu không, nó tạo một đối tượng chuỗi mới bên trong, lưu nó trong nhóm và sau đó trả về nó. Do đó, khi cùng một giá trị chuỗi được truy vấn vào lần tiếp theo, nó sẽ trả về cùng một thể hiện.

Tạo thủ công new String[""]ghi đè hành vi này bằng cách bỏ qua chuỗi ký tự chuỗi. Vì vậy, luôn luôn phải kiểm tra sự bằng nhau bằng cách equals[]so sánh chuỗi ký tự thay vì đẳng thức tham chiếu đối tượng.

Một cách đơn giản để hiểu sự khác biệt là dưới đây: - String s ="abc";String s1= "abc";String s2=new String["abc"]; if[s==s1]{            System.out.println["s==s1 is true"];        }else{            System.out.println["s==s1 is false"];        }        if[s==s2]{            System.out.println["s==s2 is true"];        }else{            System.out.println["s==s2 is false"];        }

đầu ra là  s==s1 is trues==s2 is false

Do đó, String [] mới sẽ luôn tạo một thể hiện mới.

Bất kỳ chuỗi ký tự nào được tạo bên trong nhóm ký tự chuỗi và nhóm không cho phép bất kỳ bản sao nào. Do đó, nếu hai hoặc nhiều đối tượng chuỗi được khởi tạo với cùng một giá trị bằng chữ thì tất cả các đối tượng sẽ trỏ đến cùng một nghĩa đen. String obj1 = "abc";String obj2 = "abc";

"Obj1" và "obj2" sẽ trỏ đến cùng một chuỗi ký tự và chuỗi ký tự chuỗi sẽ chỉ có một chữ "abc".

Khi chúng ta tạo một đối tượng lớp String bằng cách sử dụng từ khóa mới, chuỗi do đó được tạo sẽ được lưu trữ trong bộ nhớ heap. Bất kỳ chuỗi ký tự nào được truyền dưới dạng tham số cho hàm tạo của lớp String tuy nhiên được lưu trữ trong nhóm chuỗi. Nếu chúng ta tạo nhiều đối tượng sử dụng cùng một giá trị với toán tử mới, một đối tượng mới sẽ được tạo trong heap mỗi lần, vì toán tử mới này nên tránh. String obj1 = new String["abc"];String obj2 = new String["abc"];

"Obj1" và "obj2" sẽ trỏ đến hai đối tượng khác nhau trong heap và chuỗi ký tự chuỗi sẽ chỉ có một chữ "abc".

Ngoài ra, một điều đáng chú ý liên quan đến hành vi của các chuỗi là bất kỳ sự gán hoặc ghép mới nào được thực hiện trên chuỗi đều tạo ra một đối tượng mới trong bộ nhớ. String str1 = "abc";String str2 = "abc" + "def";str1 = "xyz";str2 = str1 + "ghi";

Bây giờ trong trường hợp trên:
Dòng 1: "abc" bằng chữ được lưu trữ trong nhóm chuỗi.
Dòng 2: "abcdef" nghĩa đen được lưu trữ trong nhóm chuỗi.
Dòng 3: Một chữ "xyz" mới được lưu trữ trong nhóm chuỗi và "str1" bắt đầu trỏ đến nghĩa đen này.
Dòng 4: Vì giá trị được tạo bằng cách nối thêm vào một biến khác, kết quả được lưu trữ trong bộ nhớ heap và chữ "ghi" được thêm vào sẽ được kiểm tra sự tồn tại của nó trong nhóm chuỗi và sẽ được tạo vì nó không tồn tại trường hợp trên.

Mặc dù nó trông giống nhau từ quan điểm của các lập trình viên, nhưng nó có tác động hiệu suất lớn. Bạn sẽ muốn sử dụng mẫu đầu tiên hầu như luôn luôn.

String str = new String["hello"]

Nó sẽ kiểm tra xem chuỗi hằng số chuỗi có chứa Chuỗi "xin chào" không? Nếu có thì nó sẽ không thêm một mục trong nhóm hằng chuỗi. Nếu không có thì nó sẽ thêm một mục trong nhóm hằng chuỗi.

Một đối tượng sẽ được tạo trong vùng nhớ heap và strcác điểm tham chiếu đến đối tượng được tạo ở vị trí bộ nhớ heap.

nếu bạn muốn strtham chiếu đến đối tượng điểm chứa trong nhóm hằng chuỗi thì người ta phải gọi một cách rõ ràngstr.intern[];  String str = "world";

Nó sẽ kiểm tra xem chuỗi hằng số chuỗi có chứa Chuỗi "xin chào" không? Nếu có thì nó sẽ không thêm một mục trong nhóm hằng chuỗi. Nếu không có thì nó sẽ thêm một mục trong nhóm hằng chuỗi.

Trong cả hai trường hợp trên, strcác điểm tham chiếu đến Chuỗi "world"có trong nhóm Hằng.

Khi bạn lưu trữ một Chuỗi như String string1 = "Hello";

trực tiếp, sau đó JVM tạo một đối tượng String với giá đã cho trong một khối bộ nhớ riêng gọi là hằng số chuỗi.

Và bất cứ khi nào chúng ta có xu hướng thử và tạo ra một Chuỗi khác như String string2 = "Hello";

JVM xác minh xem có hay không bất kỳ đối tượng Chuỗi nào có giá không đổi tồn tại trong nhóm hằng số Chuỗi, nếu vậy, thay vì tạo một đối tượng hoàn toàn mới, JVM gán tham chiếu của đối tượng hiện có cho biến mới.

Và khi chúng tôi lưu trữ String như String string = new String["Hello"];

sử dụng từ khóa mới, một đối tượng hoàn toàn mới với giá đã cho được thực hiện bất kể nội dung của nhóm hằng số Chuỗi.

Video liên quan

Chủ Đề