2016-08-17 21 views
6

Tôi đã đọc java hiệu quả edition và trang 2 số 23 nóiTại sao chúng ta thích nguyên thủy để nguyên thủy đóng hộp trong java

// Hideously slow program! Can you spot the object creation 
public static void main(String[] args) { 
    Long sum = 0L; 
    for(long i=0; i<=Integer.MAX_VALUE; i++){ 
     sum += i; 
    } 
    System.out.println(sum) 
} 

Tác giả nói rằng mã trên tạo ra 2^31 instantiations đối tượng không cần thiết. Tại sao sum + = i tạo đối tượng mới? nếu tôi thay đổi tuyên bố thành

sum = sum + 1 

không có tác dụng phụ này?

+0

Vì chúng không thay đổi. – tkausl

+0

tổng là một Long, vì vậy như @tkausl cho biết, nó là bất biến. Vì vậy, sum + = tôi giữ tái tạo các đối tượng Long mới. – FredK

+0

'sum = sum + 1' cũng có cùng tác dụng phụ. Nó sẽ tạo ra một giá trị đóng hộp mới mỗi khi nó thực thi. –

Trả lời

4

Đang cố gắng để nói lại những gì người khác đã nói một cách rõ ràng hơn:

Vấn đề với sumL ong là một tham khảo loại; nói cách khác, đó là một loại Object. Đối tượng sống trên heap; chúng được tạo ra (sử dụng "mới" và một hàm tạo) bởi JVM và "được quản lý" bởi bộ thu gom rác.

Tính năng tự động đấm cho phép bạn sử dụng biến Long kiểu tham chiếu đó giống như cách bạn sử dụng biến dài kiểu nguyên thủy.

Nhưng đối tượng Long không thể thay đổi được; một khi được tạo, giá trị của nó không bao giờ có thể thay đổi. Nhưng toàn bộ vòng lặp là liên tục thay đổi một giá trị (bằng cách tăng bộ đếm)! Vì vậy, để tăng bộ đếm, bạn phải lấy giá trị của đối tượng Long "hiện tại"; thêm 1; và thứ đó vào đối tượng Long tiếp theo. Một lần nữa, và một lần nữa, ...

Vì vậy, những gì chương trình của bạn đang làm ở đây là: tạo rác mọi lúc. Nói cách khác: những đối tượng Long được tạo; sử dụng một lần (để lấy giá trị của chúng); và sau đó chúng bị "quên" (vì không có tham chiếu đến chúng được giữ ở bất kỳ đâu). Vì vậy, họ ngay lập tức đủ điều kiện để thu gom rác .

Ý nghĩa: có thực sự là hai ảnh hưởng đến hiệu suất ở đây:

  1. tạo đối tượng không cần thiết [mà là khá rẻ trong Java, nhưng vẫn "đắt hơn" so với tính toán đơn giản trên một giá trị lâu; sau đó có lẽ chỉ là một, hai hướng dẫn CPU; trong khi tạo đối tượng sẽ dẫn đến truy cập bộ nhớ và một số hoạt động của CPU! ]
  2. Tạo tốc độ cao các đối tượng cần phải được thu gom rác.
+0

cảm ơn câu trả lời của bạn. Nó không được đề cập bởi tác giả trong cùng một phần rằng Long là bất biến gây ra sự nhầm lẫn với tôi. – raju

+0

Gợi ý: tất cả các loại tham chiếu "anh lớn" cho các kiểu nguyên thủy như Integer, Double, ... đều không thay đổi. Và đó thực sự là một điều tốt! Nhưng người ta phải nhận thức được hậu quả. Auto-boxing và những anh em lớn thường rất hữu ích, nhưng ví dụ, khi giao dịch với ** rất nhiều số **, bạn có thể thích int cũ hơn [] trên một 'ArrayList ' ... vì có ý nghĩa trên đầu của cấu trúc sau này. [trong trường hợp bạn cần phải lo lắng về hiệu suất, vì vậy xin đừng coi đây là lý do để tối ưu hóa sớm!] – GhostCat

+0

Lưu ý rằng toán tử gán '=' sẽ ** không bao giờ ** thay đổi một đối tượng. Nó sẽ chỉ đặt tham chiếu. –

2

Bởi vì mỗi khi bạn tổng hợp, bạn tạo đối tượng Long mới.

Long's là không thay đổi, do đó bạn không thể thay đổi giá trị, vì vậy tại mỗi lần lặp lại, giá trị mới được tạo bằng tổng. Nếu nó là một nguyên thủy, sau đó nó sẽ sửa đổi giá trị hiện tại của nó.

+0

Liệu 'Long' có phương thức như' setValue' hay như vậy? –

+0

@MeikVtune [No.] (http://docs.oracle.com/javase/7/docs/api/java/lang/Long.html) 'Long' là không thay đổi. –

3

sum = sum + 1 vẫn sẽ có cùng một vấn đề như sum += 1sum bên phải unboxes giá trị, sau đó thêm 1 đến nó, và cuối cùng tạo ra một đối tượng mới Long để hộp kết quả và gán biến sum tài liệu tham khảo để trỏ đến đối tượng mới được tạo.

4

Do autoboxing như biến sum của bạn không phải là một loại nguyên thủy nhưng kiểu Long (lớp wrapper), sum += i sẽ đằng sau những cảnh tạo ra một Long dụ mới vì nó là một lớp học bất biến vì vậy nó sẽ bằng cách nào đó tương đương với sum = new Long(sum.longValue() + 1)

3

Điều này xảy ra vì lớp java.lang.Long là không thay đổi. Nói cách khác, một Long mới được tạo ra trong mỗi lần lặp của vòng lặp thay vì thay đổi nguyên gốc tại chỗ. So với long nguyên thủy, hộp đóng gói Long mang nhiều hành lý. Câu lệnh thay thế của bạn, sum = sum + 1 sẽ có tác dụng tương tự như mã gốc. Thay vào đó, hãy đặt lại sum làm long sum = 0L; để tạo một long mới trên mỗi lần lặp lại, là đáng kể là rẻ hơn để tạo hơn Long.

3

sum là một kiểu dữ liệu Long là một lớp không thay đổi trong java. Trong tuyên bố sum += i;, bạn đang cố gắng thay đổi (thay đổi) giá trị sum. Trình biên dịch java sẽ tự động tạo đối tượng Long mới trong mỗi lần lặp của vòng lặp và sau đó gán tham chiếu mới được tạo này cho sum.

Do đó, tác giả của cuốn sách nói above code generates 2^31 object instantiations unnecessarily.

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