Câu hỏi Nếu == so sánh các tham chiếu trong Java, tại sao nó lại đánh giá đúng với các chuỗi này?


Như đã nói, toán tử == so sánh các tham chiếu đối tượng để kiểm tra xem chúng có liên quan đến cùng một đối tượng trên một heap hay không. Nếu vậy tại sao tôi nhận được "Bình đẳng" cho đoạn mã này?

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

        String str1 = "Str1";
        String str2 = "Str1";

        if (str1 == str2) {
            System.out.println("Equal");
        } else {
            System.out.println("Not equal");
        }
    }
}

13
2017-10-27 13:15


gốc


bạn có chắc bạn đã sử dụng == hoặc là = ?? - Jigar Joshi
Đã thay đổi ví dụ về mã, xin lỗi - Eugene
Hãy chắc chắn để nói rằng ngôn ngữ là JAVA. Các ngôn ngữ khác sẽ có triển khai khác. Dù toán tử == bị quá tải để làm cho .net. - CodingBarfield
== kiểm tra nếu refrence là như nhau trong trường hợp đối tượng được kiểm tra bình đẳng. . cách các đối tượng String được tạo ra stackoverflow.com/questions/15761283/… - Nirbhay Mishra


Các câu trả lời:


Chương trình sẽ in Equal. (Ít nhất là sử dụng Sun Hotspot và mặt trời Javac.) Ở đây nó được thể hiện trên http://ideone.com/8UrRrk

Điều này là do thực tế rằng hằng số chuỗi ký tự được lưu trữ trong một chuỗi hồ bơi và tham chiếu chuỗi có thể được tái sử dụng.

Đọc thêm:


Tuy nhiên điều này:

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

        String str1 = "Str1";
        String str2 = new String("Str1");

        if (str1 == str2) {
            System.out.println("Equal");
        } else {
            System.out.println("Not equal");
        }
    }
}

Sẽ in Not equal kể từ đó new được đảm bảo giới thiệu một tham chiếu mới.

Vì vậy, quy tắc của ngón tay cái: Luôn so sánh các chuỗi bằng cách sử dụng equals phương pháp.


37
2017-10-27 13:20



+1 để liên kết với ideone.com. Tôi muốn một webapp như thế này trong một thời gian dài. Ngay cả nghĩ về việc viết nó cho bản thân mình nhưng có nó. - Alexandre Jasmin
Để hoàn thành new String("Str1").intern() sẽ in "Equal" cũng :) - OscarRyz
@OscarRyz, Good điểm. Cảm ơn! :-) - aioobe


Java lưu trữ tất cả các chuỗi trong một bảng chuỗi nội bộ trong khi chạy. Các tham chiếu đến hai chuỗi là giống nhau vì trong bộ nhớ chúng được lưu trữ ở cùng một vị trí. Vì thế, Equal.

Tuyên bố của bạn là đúng, == so sánh các tham chiếu đối tượng. Hãy thử điều tương tự với bất kỳ lớp nào khác nhưng Strings và bạn sẽ không nhận được kết quả tương tự.


3
2017-10-27 13:19



Nó có? bạn có thể cho tôi một tham chiếu để trả lại yêu cầu này không? - Richard J. Ross III
aioobe đưa ra một giải thích tốt hơn, vì hành vi này không được đảm bảo. Và nó cũng chỉ áp dụng cho các chuỗi ký tự, không phải cho mọi chuỗi trong một chương trình. - Joey
Từ các tài liệu API Java: "Tất cả các chuỗi ký tự và các biểu thức hằng số có giá trị chuỗi được thực tập." Xem download.oracle.com/javase/1.4.2/docs/api/java/lang/… Lưu ý rằng chỉ các chuỗi không đổi sẽ được tự động thực hiện. Bạn có thể thực hiện các chuỗi được tạo động bằng cách bắt buộc String.intern () - Hannes de Jager


Mã này sẽ không in Equal.
Nhưng nếu hai dây là như nhau, trường hợp này sẽ là đặc biệt.

Bây giờ bạn đã cập nhật mã của mình, đó là trường hợp:

Một lời giải thích đơn giản (nhưng không hoàn toàn chính xác) là trình biên dịch thấy rằng hai chuỗi giống nhau và làm một cái gì đó như:

String str1 = "Str1";
String str2 = str1;

Điều thực sự xảy ra ở đây là trình biên dịch sẽ thấy chuỗi ký tự và đặt nó vào trong "String literal pool".

Như một String không thể sửa đổi (nó không thay đổi) các giá trị chữ của Strings (được tìm thấy trong quá trình biên dịch) được đặt trong một "pool".
Bằng cách này, nếu hai chuỗi chữ khác nhau có nội dung giống nhau (như trong trường hợp cụ thể này), bộ nhớ không bị lãng phí để lưu trữ "Str1" và "Str1" hai lần.


3
2017-10-27 13:17



Tôi xin lỗi, tôi đã thêm sửa chữa cho ví dụ mã. - Eugene


Mọi người, bạn quên rằng quá trình đặt các chuỗi chữ trong hồ bơi được gọi là "interning". Lớp String có một phương thức gọi là intern (). Phương pháp này đặt bất kỳ chuỗi vào hồ bơi, ngay cả khi nó không phải là trong hồ bơi ban đầu (không phải chữ). Điều này có nghĩa là mã như thế này:

String a = "hello";
String b = new String("hello");
b = b.intern();

System.out.println(a == b);

sẽ in "true". Bây giờ, tại sao một người nào đó cần điều này? Như bạn có thể tưởng tượng, so sánh chuỗi a.equals(b) có thể mất nhiều thời gian nếu các chuỗi có cùng độ dài nhưng khác nhau gần hết. (Chỉ cần nhìn vào mã nguồn .equals ().).

Tuy nhiên, việc so sánh các tham chiếu trực tiếp giống như so sánh các số nguyên (các con trỏ trong C nói), tức là gần ngay lập tức.

Vì vậy, những gì hiện này cung cấp cho bạn? Tốc độ. Nếu bạn phải so sánh cùng một chuỗi nhiều, nhiều lần, hiệu suất chương trình sẽ được hưởng lợi rất nhiều nếu bạn thực tập các chuỗi này. Tuy nhiên, nếu bạn sẽ so sánh các chuỗi chỉ một lần, sẽ không có hiệu năng đạt được khi quá trình interning tự sử dụng equals ().

Tôi hy vọng điều này giải thích điều này.

cảm ơn


2
2017-10-27 14:31





Các ý kiến ​​ở trên đã tóm tắt nó khá tốt.

Tôi không có một môi trường Java tiện dụng, nhưng cố gắng sau đây nên làm rõ những điều cho bạn (hy vọng điều này hoạt động như tôi dự đoán).

String str1 = "Str1";  
String str2 = "Str"; str2 += "1";

Hiện tại nên in Không bằng


0
2017-10-27 13:50