2014-09-10 19 views
7

Tôi đã tìm thấy một điều khá lạ đối với tôi khi làm việc với Java. Có lẽ đó là một điều bình thường, nhưng tôi không hiểu tại sao nó hoạt động theo cách này.Java. Tại sao nó hoạt động khác với các ký tự tiếng Anh và tiếng lóng?

Tôi có một mã như thế này:

Character x = 'B'; 
Object o = x; 
System.out.println(o == 'B'); 

Nó hoạt động tốt và đầu ra là "true". Sau đó, tôi thay đổi tiếng Anh B thành slavic B (Б):

Character x = 'Б'; 
Object o = x; 
System.out.println(o == 'Б'); 

Bây giờ đầu ra là "sai". Làm thế nào mà? Bằng cách này, đầu ra vẫn là "true" nếu tôi so sánh biến x với 'Б' trực tiếp, nhưng khi tôi làm điều đó thông qua một Object nó hoạt động khác nhau.

Bất kỳ ai, vui lòng giải thích hành vi này?

Trả lời

8

Không có quyền anh - chỉ sử dụng char - bạn sẽ ổn thôi. Tương tự, nếu bạn sử dụng equals thay vì ==, bạn sẽ ổn. Vấn đề là bạn đang so sánh các tham chiếu cho các giá trị được đóng gói bằng cách sử dụng ==, chỉ kiểm tra danh tính tham chiếu. Bạn đang nhìn thấy một sự khác biệt vì cách tự động boxing hoạt động. Bạn có thể thấy điều tương tự với Integer:

Object x = 0; 
Object y = 0; 
System.out.println(x == y); // Guaranteed to be true 

Object x = 10000; 
Object y = 10000; 
System.out.println(x == y); // *May* be true 

Về cơ bản giá trị "nhỏ" đã được lưu trữ cơ quan đại diện đóng hộp, trong khi giá trị "lớn hơn" có thể không.

Từ JLS 5.1.7:

Nếu p giá trị được đóng hộp là một số nguyên đen của loại int giữa -128 và 127 bao gồm (§3.10.1), hoặc boolean đen đúng hay sai (§3.10. 3), hoặc một ký tự theo nghĩa đen giữa '\ u0000' và '\ u007f' bao gồm (§3.10.4), sau đó cho a và b là kết quả của bất kỳ chuyển đổi quyền anh nào của p. Luôn luôn là trường hợp a == b.

Lý tưởng nhất, việc đánh giá một giá trị nguyên thủy sẽ luôn mang lại một tham chiếu giống hệt nhau. Trong thực tế, điều này có thể không khả thi khi sử dụng các kỹ thuật triển khai hiện có. Quy tắc trên là sự thỏa hiệp thực dụng, yêu cầu các giá trị chung nhất định luôn được đóng hộp thành các đối tượng không thể phân biệt được. Việc triển khai có thể lưu vào bộ nhớ cache, lười biếng hoặc háo hức. Đối với các giá trị khác, quy tắc không cho phép bất kỳ giả định nào về danh tính của các giá trị được đóng hộp trên phần của lập trình viên. Điều này cho phép (nhưng không yêu cầu) chia sẻ một số hoặc tất cả các tài liệu tham khảo này. Lưu ý rằng các chữ số nguyên của loại long được phép, nhưng không bắt buộc phải được chia sẻ.

Điều này đảm bảo rằng trong hầu hết các trường hợp phổ biến, hành vi sẽ là hành vi mong muốn, không áp đặt hình phạt hiệu suất quá mức, đặc biệt là trên các thiết bị nhỏ. Ví dụ: ít triển khai bộ nhớ hạn chế hơn, bộ nhớ cache tất cả các giá trị charshort cũng như các giá trị intlong trong phạm vi từ -32K đến + 32K.

Phần về "một ký tự chữ giữa \u0000 and \ u007f`" đảm bảo rằng đóng hộp ký tự ASCII sẽ được lưu trữ, nhưng không phi ASCII đóng hộp ký tự.

2

khi bạn làm

Character x = 'B' 

nó gọi Character.valueOf(C)

2: invokestatic #16     // Method java/lang/Character.valueOf:(C)Ljava/lang/Character; 

mà lưu trữ

Phương pháp này sẽ luôn luôn giá trị bộ nhớ cache trong phạm vi '\ u0000' thành '\ u007F' , bao gồm và có thể lưu các giá trị khác ngoài phạm vi này.

public static Character valueOf(char c) { 
    if(c <= 127) { // must cache 
     return CharacterCache.cache[(int)c]; 
    } 
    return new Character(c); 
} 

tương tự

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