2010-06-24 43 views
37

Tôi thấy rất nhiều mã java nơi mà android thích có các nhà phát triển sử dụng các lớp bên trong tĩnh. Riêng đối với các mẫu như ViewHolder Pattern trong Danh sách tùy chỉnh.Tại sao Android lại thích các lớp tĩnh hơn

Tôi không chắc chắn sự khác biệt giữa các lớp tĩnh và không tĩnh. Tôi đã đọc về nó nhưng nó dường như không có ý nghĩa khi liên quan đến hiệu năng hoặc bộ nhớ.

Trả lời

62

Đó không chỉ là nhà phát triển Android ...

Lớp bên trong không tĩnh luôn giữ tham chiếu ngầm định đối tượng kèm theo. Nếu bạn không cần tham khảo đó, tất cả nó là bộ nhớ chi phí. Xem xét việc này:

class Outer { 
    class NonStaticInner {} 
    static class StaticInner {} 
    public List<Object> foo(){ 
     return Arrays.asList(
      new NonStaticInner(), 
      new StaticInner()); 
    } 
} 

Khi bạn biên dịch nó, những gì bạn nhận được sẽ là một cái gì đó như thế này:

class Outer { 
    Outer(){} 
    public List<Object> foo(){ 
     return Arrays.asList(
      new Outer$NonStaticInner(this), 
      new StaticInner()); 
    } 
} 
class Outer$NonStaticInner { 
    private final Outer this$0; 
    Outer$NonStaticInner(Outer enclosing) { this$0 = enclosing; } 
} 
class Outer$StaticInner { 
    Outer$StaticInner(){} 
} 
+2

Đó là sự thật, nhưng có nhiều hơn - đôi khi bạn không có một tham chiếu đến lớp bên ngoài và vẫn muốn khởi tạo bên trong (nếu nó có thể nhìn thấy). – ognian

+4

+1 cho ấn tượng những gì trình biên dịch sẽ tạo ra từ nguồn đầu vào – Seven

+0

Không thể một lớp bên trong không tĩnh khai báo rõ ràng một tham chiếu đến bên ngoài (chỉ cần tự khởi tạo nó), do đó cho tốt nhất của cả hai thế giới: tham chiếu ngoài mà không có chi phí bộ nhớ tĩnh? Ngoài ra, không phải là một lớp bên trong tĩnh không reentrant, do đó hữu ích chỉ trong trường hợp một trường hợp duy nhất của nó là cần thiết? – samosaris

14

Lớp bên trong tĩnh (ví dụ: các lớp được khai báo bên trong một lớp khác có từ khóa static) tương tự như các lớp "bình thường" ngoại trừ bạn không gây ô nhiễm không gian tên của gói. Đó là sự khác biệt (chỉ) của họ và lợi ích và tôi tin rằng đó là lý do bạn thấy nó trong Android.

Sử dụng các lớp bên trong tĩnh khi mục đích của lớp được thắt chặt với lớp chính, nhưng không phụ thuộc vào các thể hiện của lớp đó. Điều này thường được coi là một thực hành tốt.

+0

Bạn có thể đi vào chi tiết hơn về lớp bên trong tĩnh và cấu thành lớp bên trong không? Điều này là hấp dẫn – Mike

24

Sự khác biệt chính giữa các lớp bên trong tĩnh và không tĩnh là lớp bên trong không tĩnh có quyền truy cập vào các thành viên khác của lớp bên ngoài, ngay cả khi chúng là riêng tư. Các lớp bên trong không tĩnh là một "phần" của lớp ngoài. Bạn không thể tạo và cũng không thể tồn tại mà không có một thể hiện của một lớp bên ngoài. Một hệ quả của điều này là một thể hiện của một lớp bên trong không tĩnh bị phá hủy khi thể hiện của lớp bên ngoài bị phá hủy.

Các lớp bên trong tĩnh, giống như các lớp ngoài thông thường. Sống và chết một mình. Bạn không cần một cá thể của lớp ngoài để lớp bên trong tồn tại. Điều đó có nghĩa là họ cũng có chu kỳ sống riêng. Chúng bị phá hủy khi người thu gom rác quyết định tiêu diệt chúng.

Điều này ảnh hưởng đến bộ nhớ và/hoặc hiệu suất như thế nào? Tôi thực sự không biết. :)

+2

"Làm thế nào điều này ảnh hưởng đến bộ nhớ và/hoặc hiệu suất?" Nó sẽ ngăn chặn rò rỉ bộ nhớ. Có một lớp bên trong tĩnh ngăn cản nó tham chiếu đến Activity/Fragment, vì lớp bên trong tĩnh không thể truy cập biến thành viên bên ngoài. Nếu chúng ta có rò rỉ bộ nhớ trên Activity, và Activity đó giữ một tham chiếu nhiều đối tượng nặng (như Views), nó sẽ tiêu thụ bộ nhớ không cần thiết và làm chậm hiệu năng. – aldok

4

Nếu bạn biên soạn lại một lớp bên trong (hoặc xem nó sử dụng gỡ lỗi), bạn có thể thấy rằng có tạo mã để truy cập vào cá thể của lớp ngoài được sử dụng để tạo chúng. Chi phí cho điều này là nhiều bộ nhớ cho con trỏ bổ sung, nhiều cpu hơn cho việc thu gom rác vì con trỏ bổ sung cần kiểm tra, và nếu bạn muốn chọn nit, thời gian biên dịch dài hơn. Tạo các cá thể của các lớp bên trong không tĩnh phức tạp hơn một chút bởi vì bạn cần một cá thể của lớp bên ngoài để tạo chúng.

Có thể kiểm soát khả năng hiển thị của cả lớp tĩnh và không tĩnh. Thông thường chúng là riêng tư nếu việc triển khai của chúng được liên kết chặt chẽ với các chi tiết bên trong của lớp bên ngoài và nhà phát triển không nghĩ rằng mã có thể được sử dụng lại. Theo nghĩa này, chúng không tốt hơn các hàm riêng. Các lớp bên trong có thể được công khai trong các trường hợp như Map.Entry, nơi lớp bên trong được kết nối chặt chẽ với giao diện được lớp tiếp xúc và nhà phát triển không nghĩ rằng Map.Entry có thể được sử dụng mà không có một loại Bản đồ. Cả hai loại có quyền truy cập vào các thành viên riêng của lớp bên ngoài và lớp bên ngoài có quyền truy cập vào các thành viên riêng của lớp bên trong.

Trường hợp của các lớp bên trong tĩnh và không tĩnh là rác được thu thập như mọi lớp khác.Không có kết nối đặc biệt nào giữa bộ sưu tập grabage của lớp bên ngoài và bộ sưu tập rác của lớp bên trong.

Trong trường hợp triển khai các lớp UI như xoay hoặc android, bạn sẽ thấy các lớp bên trong tĩnh vì chúng được xử lý như hàm riêng tư. Các lớp này không được phát triển để có thể sử dụng lại bên ngoài lớp bên ngoài và được kết nối chặt chẽ với việc thực hiện bên trong lớp bên ngoài. Không có lý do gì để phơi bày chúng và để đảm bảo chúng có thể làm việc trong nhiều trường hợp hơn là bối cảnh cụ thể của các yêu cầu lớp ngoài.

4

Một thể hiện lớp bên trong không tĩnh giữ một tham chiếu đến cá thể lớp bên ngoài trong khi một cá thể lớp bên trong tĩnh thì không.

Điều này phù hợp với bộ nhớ ứng dụng vì tham chiếu ẩn có thể dẫn đến rò rỉ bộ nhớ - bộ thu gom rác không thể thu thập cá thể lớp bên ngoài cho đến khi không có tham chiếu nào tồn tại. Ngoài ra, tham chiếu bổ sung cũng cần bộ nhớ, điều này có thể có liên quan nếu một số lượng lớn các cá thể được sử dụng.

class Outer{ 
    class Inner{//Only works with non static inner class 
      public Outer getOuter(){return Outer.this;} 
    } 
} 

Nó cũng thích hợp cho việc sử dụng nó, các tham chiếu đến các lớp bên ngoài là một đối số ctor của lớp bên trong, để tạo ra một đối tượng lớp bên trong tĩnh không mới, bạn phải gọi ctor như một memberfunction trên Ví dụ của lớp bên ngoài hoặc từ bên trong một hàm thành viên của lớp bên ngoài. Điều này có nghĩa rằng bạn không thể có một thể hiện của lớp bên trong mà không có một thể hiện của lớp bên ngoài.

Outer.Inner in = new Outer().new Inner(); 
Các vấn đề liên quan