2010-06-12 37 views
23

Có sự khác biệt về hiệu quả (ví dụ: thời gian thực thi, kích thước mã, v.v.) giữa hai cách làm việc này không? Dưới đây là những ví dụ giả tạo tạo đối tượng và không làm gì cả, nhưng kịch bản thực tế của tôi có thể tạo Chủ đề, Người nghe mới, v.v. Giả sử các đoạn mã sau xảy ra trong một vòng lặp để có thể tạo sự khác biệt.Ẩn ý nghĩa hiệu quả lớp ẩn danh Java

Sử dụng đối tượng ẩn danh:

void doSomething() { 
    for (/* Assume some loop */) { 
     final Object obj1, obj2; // some free variables 

     IWorker anonymousWorker = new IWorker() { 
      doWork() { 
       // do things that refer to obj1 and obj2 
      } 
     }; 
    } 
} 

Định nghĩa một lớp đầu tiên:

void doSomething() { 
    for (/* Assume some loop */) { 
     Object obj1, obj2; 
     IWorker worker = new Worker(obj1, obj2); 
    } 
} 

static class Worker implements IWorker { 
    private Object obj1, obj2; 
    public CustomObject(Object obj1, Object obj2) {/* blah blah */} 

    @Override 
    public void doWork() {} 
}; 
+3

Bạn nên làm những gì bạn tin là rõ ràng nhất và dễ hiểu nhất, sự khác biệt hiệu suất sẽ nhỏ hơn nhiều so với công việc bạn làm trong doWork() để nó không tạo sự khác biệt. Nếu tôi ước tính sự khác biệt, tôi sẽ mong đợi khoảng 10 nano giây. –

+0

Trừ khi bạn đang thực hiện mã quan trọng và bài giảng của bạn không giữ – LegendLength

Trả lời

37

chỉ khác biệt thực tế giữa các lớp ẩn danh và lớp cấp cao là lớp ẩn danh sẽ giữ tham chiếu ngầm định với lớp bên ngoài.

Điều này sẽ không tự biểu hiện hiệu suất, nhưng sẽ tác động đến bạn nếu bạn đã từng sắp xếp các lớp này.

+9

Nó sẽ tác động đến hiệu suất nếu nó không có ý nghĩa đối với tham chiếu đến lớp bên ngoài để được giữ sống - đặc biệt là khi xe tải rác lăn xung quanh. Bạn sẽ thu thập nhiều rác hơn cùng một lúc thay vì để cho lớp bên ngoài rơi ra khỏi phạm vi khi cần thiết. Không phải là một sự khác biệt lớn nhưng nó không phải là để được bỏ qua. – dcow

+1

@dcow quan tâm giải thích, tôi đã không chính xác bắt trôi của bạn khi bạn nói '... cho tham chiếu đến lớp bên ngoài để được giữ sống' Ý của bạn là nếu lớp bên trong giữ tham chiếu đến lớp bên ngoài? – Cu7l4ss

+3

@ Cu7l4ss - các lớp bên trong * làm * giữ tham chiếu đến lớp bên ngoài. Nó không phải là bình thường nhìn thấy được nhưng nó là có –

16

Nên có ít nếu có chênh lệch hiệu suất. Nếu có sự khác biệt, nó sẽ ở mức độ không đáng lo ngại.

IMO, bạn nên tập trung vào viết mã có thể đọc và duy trì và bỏ qua các vấn đề hiệu suất "vi mô" cho đến khi bạn có rõ ràng bằng chứng cho thấy chúng quan trọng ... dựa trên lược tả ứng dụng.

(Đối với hồ sơ, khi một lớp bên trong vô danh đề cập đến một final trong phạm vi bao quanh, điều này được thực hiện ở cấp bytecode bằng các đối số hàm dựng ẩn và thuộc tính ẩn ẩn. bytecode mà bạn nhận được từ việc triển khai khác của mình.)

16

Điều quan trọng là nhận ra rằng các lớp ẩn danh vẫn là các lớp đã được biết và được biên dịch đầy đủ lúc biên dịch. Thực tế là, bạn đang định nghĩa một lớp ẩn danh, có lẽ với nhiều phương thức và các trường v.v ... trong vòng lặp, không có nghĩa là thời gian chạy phải biên dịch loại đó trên mỗi lần lặp.

Do đó, bất kỳ sự khác biệt nào về hiệu suất giữa hai phương pháp đều không đáng kể. Các yếu tố quan trọng cần xem xét là những thứ như khả năng đọc, khả năng sử dụng lại, khả năng thử nghiệm, v.v.

1

Suy đoán về hiệu suất mã là cách tuyệt vời để lãng phí thời gian của bạn. Không có gì so sánh để thực sự đo điểm chuẩn mã. Nếu bạn lo lắng về hiệu suất, hãy đo mã số. Nếu bạn nghi ngờ rằng mã của bạn là tối ưu hóa phụ, hãy cấu hình mã để tìm ra thời gian được sử dụng, sau đó cố gắng cải thiện các phần đó. Tại thời điểm này nó có thể thích hợp để thực sự nghiên cứu mã byte để xem liệu nó có thể cung cấp cho bạn một gợi ý mà việc thực hiện có hiệu quả hơn không.

Khi bạn đã làm điều đó, đo mã lại để đảm bảo rằng bạn không làm mọi việc tồi tệ hơn, ví dụ bằng cách làm cho mã xấu hơn và khó bảo trì hơn.

3

Tôi thực sự đã nhận thấy một lần truy cập hiệu suất quan trọng khi khởi tạo nhiều phiên bản của một lớp ẩn danh.

Suy nghĩ nếu có thể là do lớp địa phương là tĩnh tôi đã xóa và điều đó không có sự khác biệt.

Trong trường hợp của tôi, tôi đã làm điều gì đó 1000 chọn 3 lần là 499.500. Phiên bản với các lớp địa phương (bất kể tĩnh hay không) mất 26 giây và phiên bản với lớp vô danh chức năng vô danh mất 2 phút 20 giây.

+0

Có nhiều điều cần xem xét khi các lớp lồng nhau cũng có thể gây ra các tác dụng phụ phụ nếu được sử dụng nhiều. Ví dụ, bất kỳ nỗ lực nào để truy cập các thành viên private hoặc các phương thức của một đối tượng khác (chẳng hạn như đối tượng bên ngoài) sẽ kết thúc bằng một phương thức công khai (một getter đơn giản) được tạo ra và sử dụng thay thế. Đó là điều bạn nên ghi nhớ khi lồng ghép logic. Không có liên kết cho điều này, nhưng đã tìm thấy nó một thời gian trước đây trong đặc tả JVM. – Pijusn

+0

Sẽ rất hữu ích nếu bạn cung cấp mã điểm chuẩn để hỗ trợ điều này. –

3

Về hiệu suất, bạn nên cân nhắc xem có nên tạo lớp bên trong hay không.

Một ví dụ thực hành xấu là một cái gì đó như:

public List<String> someMethod() { 
     return new ArrayList<String>() {{ 
         add("Item one"); 
         add("Item two"); 
       }}; 
} 

Trong khi tiện cú pháp này có vẻ thông minh trong nháy mắt đầu tiên, điều này (thường không được chú ý) sẽ tạo ra một lớp bên trong vô danh mà đối tượng giữ một tham chiếu đến thể hiện bên ngoài . Vì đối tượng này cũng được gán cho bên ngoài là giá trị kết quả của someMethod, bạn không thể chắc chắn người gọi của mình làm gì với danh sách này. Nếu anh ta đặt cá thể ArrayList kết quả vào một số biến tĩnh, đối tượng hiện tại của bạn sẽ được giữ mãi mãi!

+0

Sau đó, làm thế nào để bạn trả lại danh sách? đề xuất của bạn để thực hành tốt hơn là gì? Cảm ơn – jlanza

+0

Hỏi ý kiến ​​ba tuổi? Ok, tốt, vì Java 7 sẽ trả về mảng Arrays.asList ("Item one", "Item two"); Phải không? – Det

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