2012-04-14 40 views
42

Tôi đang đọc SCJP Java 6 của Kathy Sierra và Bert Bates và cuốn sách này làm tôi bối rối. Trên trang 245, họ tuyên bố rằng đoạn mã dưới đây.Sử dụng toán tử == trong Java để so sánh các đối tượng bao bọc

Integer i1 = 1000; 
Integer i2 = 1000; 
if(i1 != i2) 
System.out.println("different objects"); 

//Prints output 
different objects 

Sau đó, trên trang rất cạnh họ có đoạn mã sau

Integer i3 = 10; 
Integer i4 = 10; 
if(i3 == i4) 
System.out.println("same objects"); 

//Prints output 
same objects 

Tôi rất bối rối! Khi tôi thử điều này một mình, có vẻ như bạn không thể sử dụng == để so sánh cùng cách bạn sẽ sử dụng phương thức equals(). Sử dụng == luôn cho tôi 'sai' ngay cả khi các biến Số nguyên được đặt thành cùng một giá trị (ví dụ: 10). Tôi có đúng không? Sử dụng == để so sánh cùng một đối tượng Số nguyên (có cùng giá trị) sẽ luôn dẫn đến 'false'

+1

Tôi nghĩ rằng liên kết này có thể giúp bạn: http: //stackoverflow.com/questions/1514910/when-comparing-two-integers-in-java-does-auto-unboxing-occur – Tarik

+1

bản sao của http://stackoverflow.com/questions/5277881/why-arent-integers- cached-in-java – Patrick

+1

Và điều này: http://stackoverflow.com/questions/5117132/int eger-wrapper-objects-share-the-same-instances-only-trong-the-value-127, http://stackoverflow.com/questions/8427416/why-is-true-for-some-integer-objects – Patrick

Trả lời

51

Chìa khóa cho câu trả lời được gọi là đối tượng interning. Java thực tập số nhỏ (ít hơn 128), vì vậy tất cả các trường hợp của Integer(n) với n trong phạm vi được lấy là giống nhau. Số lớn hơn hoặc bằng 128 không được tập trung, do đó Integer(1000) đối tượng không bằng nhau.

+1

Wow! Tôi cũng thấy điều đó. Tại sao?? Điều đó thật khó hiểu. Lý do đằng sau điều này là gì? – dido

+8

lưu ý rằng chỉ có đối tượng thu được từ literals, autoboxing và 'Integer.valueOf()' là các đối tượng bên trong trong khi các đối tượng được tạo với 'Integer' mới luôn là các đối tượng riêng biệt –

+0

Tôi dường như nhớ rằng cũng đi cho các chuỗi nhỏ, nhưng không chắc chắn cho dù điều này là đúng sự thật và nếu như vậy, những gì được coi là một chuỗi nhỏ. Bạn có biết gì về điều đó không? –

7

Câu trả lời ở trên về Interning là đúng. Một cái gì đó để xem xét mặc dù nếu bạn làm:

Integer i3 = new Integer(10); 
Integer i4 = new Integer(10); 

Bạn sẽ không có đối tượng mới vì bạn đã tạo ra các đối tượng mới explictly. Nếu bạn viết mã như sau nó sẽ được interned:

Integer i3 = Integer.valueOf(10); 
Integer i4 = Integer.valueOf(10); 

Bây giờ chúng sẽ là cùng một đối tượng một lần nữa. Nếu bạn nhìn vào phương thức valueOf bên trong lớp Integer.java trong tệp src.zip, bạn có thể thấy nó kiểm tra xem giá trị của int nằm ngoài -128 đến 127 hay không, nó gọi lớp Integer mới nếu không nó tải nó từ bộ nhớ cache.

14

Nếu bạn nhìn vào các mã nguồn cho Integer bạn sẽ thấy rằng Integer.valueOf(int)hồ tất cả các giá trị -128 đến 127. Lý do là giá trị Integer nhỏ được sử dụng thường xuyên và do đó đáng được gộp/cache.

Taken thẳng từ Integer.java:

public static Integer valueOf(int i) { 
    if(i >= -128 && i <= IntegerCache.high) 
     return IntegerCache.cache[i + 128]; 
    else 
     return new Integer(i); 
} 

Lưu ý rằng tổng hợp này là thực hiện cụ thể và không có bảo đảm của dãy gộp.

Câu trả lời về thực tập là đúng trong khái niệm, nhưng không đúng với thuật ngữ. Thực tập trong Java thường ngụ ý rằng thời gian chạy Java đang thực hiện việc gộp (chẳng hạn như thực tập của String). Trong trường hợp của Integer, chính lớp đó đang làm việc gộp nhóm. Không có ma thuật JVM nào liên quan.

+1

Trên thực tế, bộ nhớ đệm của các đối tượng 'Integer' cho các giá trị' int' trong phạm vi [-128, 127] được chỉ định trong [tài liệu API] (http://docs.oracle.com/javase/7/docs/api /java/lang/Integer.html#valueOf%28int%29), do đó, một phần của phạm vi được, trên thực tế, được bảo đảm. –

2
Integer i1 = 1000; 
Integer i2 = 1000; 

Hộp biên dịch 'int' là đối tượng Integer. Để làm điều này nó chuyển đổi các nguồn như sau:

Integer i1 = Integer.valueOf(1000); 
Integer i2 = Integer.valueOf(1000); 

Bây giờ valueOf có thể là một cuộc gọi đơn giản để new Integer(1000) tuy nhiên việc tạo ra một đối tượng Integer mới mỗi khi một int được đóng hộp sẽ có chi phí cả về thời gian và không gian. Để tránh điều này, lớp Integer giữ một mảng các đối tượng Integer cho một phạm vi giới hạn các giá trị int.

if(value> maxRange || value< minRange){ 
    //not in pool return new Integer 
    return new Integer(value); 
}else{ 
    //return pooled Integer object 
    //for the value, pool contains all Integer 
    //values from minRange to maxRange 
    return integerPool[value-minRange]; 
} 

Tốc độ đạt được so với bộ nhớ bị mất điều này có thể được điều chỉnh bằng cách đặt phạm vi với đối số jvm khi bắt đầu chương trình (mặc định là mặc định là -127 đến 128).

0

Khi toán tử Java == được sử dụng để so sánh bất kỳ thứ gì ngoài các kiểu nguyên thủy, nó kiểm tra tính bình đẳng tham chiếu; điều này được áp dụng ngay cả khi những thứ được so sánh được bao bọc bởi nguyên thủy. Hơn nữa, phương thức valueOf và câu lệnh autoboxing được tạo bởi trình biên dịch thường tự do trả về một đối tượng mới sẽ không được tham chiếu bằng bất kỳ tham chiếu hiện có nào khác hoặc trả về tham chiếu đến đối tượng hiện có (dĩ nhiên, , tham chiếu bằng bất kỳ tham chiếu đã tồn tại nào xác định cùng một đối tượng). Việc triển khai được yêu cầu duy trì một "hồ bơi" của các trường hợp Integer cho các giá trị từ -128 đến 127, sao cho tất cả các cuộc gọi đến Integer.valueOf trên bất kỳ số cụ thể nào trong phạm vi đó sẽ trả về tham chiếu cho cùng một đối tượng, ngoại trừ việc triển khai sẽ miễn phí làm điều gì đó như

static Integer [] intPool = new Integer[256]; 

public Integer valueOf(int n) 
{ 
    int hash = (n*0x18675309) >>> 24; 
    Integer instance = intPool[n]; 
    if (instance == null && instance.value != n) 
    { 
    instance = new Integer(n); 
    intPool[hash] = instance ; 
    } 
    return instance; 
} 

tôi không đặc biệt mong đợi Java triển khai để làm một cái gì đó như thế, vì trong nhiều trường hợp, các "bộ nhớ cache hit" tỷ lệ có thể là gần 0% và thời gian phụ dành tìm kiếm các trường hợp trong bộ nhớ cache sẽ bị lãng phí. Tuy nhiên, không bao giờ có bất kỳ đảm bảo rằng tham chiếu được trả lại bởi instanceOf sẽ không khớp với tham chiếu trước đó được trả về bởi phương thức đó (ngay cả khi nó không khớp với tham chiếu cuối cùng được trả về bằng phương pháp đó, một số thuật toán lưu vào bộ nhớ cache có thể khiến trả lại tham chiếu trước đó, đặc biệt nếu hồ bơi được chia sẻ bởi nhiều luồng mà không khóa. tham chiếu trả về so sánh bằng nhau). Chỉ tham chiếu đến Integer đối tượng được tạo trực tiếp bằng cách sử dụng hàm tạo new Integer(n) được đảm bảo là duy nhất; mã dự kiến ​​bất kỳ tham chiếu nào được trả về bởi valueOf để không khớp với bất kỳ tham chiếu nào được trả lại bởi valueOf, mà không thực sự quan sát thấy rằng nó không khớp, nên được coi là bị hỏng.

0

So sánh chuỗi và so sánh số nguyên bằng cách sử dụng == và! = Cho kết quả boolean không như chúng tôi mong đợi. Hãy cẩn thận và đảm bảo kết quả không rõ có thể không cản trở hiệu suất, độ tin cậy và độ chính xác của phần mềm.

0

"==" luôn so sánh vị trí bộ nhớ hoặc tham chiếu đối tượng của các giá trị. bằng phương pháp luôn luôn so sánh các giá trị. Nhưng bằng cách gián tiếp cũng sử dụng toán tử "==" để so sánh các giá trị. Integer sử dụng Integer cache để lưu trữ các giá trị từ -128 đến + 127.If toán tử == được sử dụng để kiểm tra bất kỳ giá trị nào trong khoảng từ -128 đến 127 thì nó trả về giá trị true. nếu có giá trị trong khoảng -128 đến 127 như

Integer i1 = -128; 
Integer i2 = -128; 
System.out.println(i1 == i2); // returns true 

khác ngoài phạm vi trên thì nó trả về false

Integer i1 = 1000; 
Integer i2 = 1000; 
System.out.println(i1 == i2); // returns false 

Refer the link đối với một số thông tin bổ sung

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