2009-06-22 31 views
17

Các lớp bên trong thường được sử dụng trong Java? Đây có giống như các lớp lồng nhau không? Hoặc có được thay thế trong Java bởi một cái gì đó tốt hơn? Tôi có một cuốn sách trên phiên bản 5 và nó có một ví dụ sử dụng một lớp bên trong, nhưng tôi nghĩ rằng tôi đọc một cách khác biệt rằng các lớp bên trong là "xấu".Các lớp bên trong thường được sử dụng trong Java? Họ có "xấu" không?

Tôi không có ý tưởng và đã hy vọng những suy nghĩ về nó.

Cảm ơn bạn.

+0

http://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class –

+2

"Thuật ngữ: Các lớp lồng nhau được chia thành hai loại: tĩnh và không tĩnh. Các lớp lồng nhau được static được khai báo đơn giản được gọi là các lớp lồng nhau tĩnh. Các lớp lồng nhau không tĩnh được gọi là các lớp bên trong. - Từ http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html –

+0

Có thể trùng lặp http://stackoverflow.com/questions/487126/is-usage-of-anonymous-classes -in-java-coi-bad-style-or-good –

Trả lời

28

lớp Inner thường được sử dụng, và một cái gì đó rất giống nhau - lớp nặc danh - là thực tế không thể thiếu, vì chúng là những điều gần gũi nhất Java phải đóng cửa. Vì vậy, nếu bạn không thể nhớ nơi bạn nghe nói rằng các lớp bên trong là xấu, cố gắng quên nó!

+1

chỉ không đề cập đến đôi khởi tạo cú đúp ... – skaffman

+0

đóng cửa về cơ bản cho phép một đoạn mã được vận chuyển ở một nơi khác và vẫn tham chiếu đến môi trường ban đầu của nó. Nó có thể rất, rất đẹp. –

+2

@skaffman - ack! Chỉ cần nhìn họ lên, không thể tin được. Bạn nghĩ bạn đã tạo Danh sách ? Đoán lần nữa, bạn của tôi, hãy đoán lại! –

3

Tôi không nghĩ chúng là xấu hay xấu. Có lẽ chúng không được sử dụng rộng rãi, nhưng chúng có nhiều công dụng, gọi lại là một trong số chúng. Một lợi thế đặc biệt là chúng có thể mở rộng từ một lớp khác với lớp bên ngoài, vì vậy bạn có thể có nhiều thừa kế.

Tôi có thể nói rằng một trong những vấn đề với các lớp bên trong là cú pháp của họ có phần "xấu xí". Đó là điều khiến một số người nản chí. Ở đây tại nơi làm việc có rất nhiều người trong số họ.

16

Chúng không phải là "xấu" như vậy.

Họ có thể dễ bị lạm dụng (lớp bên trong của các lớp bên trong, ví dụ). Ngay sau khi lớp bên trong của tôi trải dài hơn một vài dòng, tôi thích trích xuất nó vào lớp riêng của mình. Nó hỗ trợ khả năng đọc và thử nghiệm trong một số trường hợp.

Có một Gotcha mà không phải là ngay lập tức rõ ràng, và đáng ghi nhớ. Bất kỳ lớp nội bộ không phải là static sẽ có tham chiếu ngầm định đến lớp bên ngoài xung quanh (một tham chiếu ngầm định 'này'). Đây không phải là một vấn đề bình thường, nhưng nếu bạn sắp xếp theo thứ tự lớp bên trong (nói, sử dụng XStream), bạn sẽ thấy rằng điều này có thể khiến bạn đau buồn bất ngờ.

1

Chúng hữu ích và có thể được sử dụng rất phổ biến. Trong khi bạn nên thận trọng về việc lạm dụng chức năng, họ không phải chịu trách nhiệm lạm dụng nhiều hơn bất kỳ tính năng ngôn ngữ nào khác.

2

Một ví dụ điển hình của một lớp bên trong là việc thực hiện lặp cho một loại bộ sưu tập nhất định. Một lớp của nó thực hiện một giao diện công cộng, nhưng không có kinh doanh tồn tại ngoại trừ việc kết hợp với một lớp khác. Nó cho phép bạn mô hình hóa những thứ trong C++, bạn sẽ bị buộc phải làm với người điều hành bạn.

2

Các lớp bên trong không tĩnh có thể ẩn vấn đề về hiệu suất. Họ có quyền truy cập vào các lĩnh vực thành viên trên lớp bao quanh, nhưng không trực tiếp, nhưng thông qua getters được tạo tự động. Điều này sẽ chậm hơn sau đó chỉ cần sao chép các thành viên của lớp kèm theo vào lớp bên trong.

Một số vấn đề khác với các lớp bên trong không tĩnh được mô tả here

0

Điều quan trọng cần nhớ là bạn đang đi đến thương mại linh hoạt cho sự đơn giản và sự gắn kết bằng cách làm cho hai lớp kết chặt chẽ hơn. Bạn có thể muốn các lớp được ràng buộc chặt chẽ, nhưng bạn đang từ bỏ khả năng chuyển đổi các lớp khác một cách minh bạch sang vị trí của lớp hiện tại của bạn bằng cách không định nghĩa lớp của bạn từ một giao diện bên ngoài lớp chứa.

0

xem xét sau Ví dụ:

public class OuterClass { 

private AnonymousInnerClass anonymousInnerClass = new AnonymousInnerClass() { 
    @Override 
    protected void printAboutme() { 
     System.out.println("AnonymousInnerClass.printAboutMe........."); 
     Class clazz = this.getClass(); 

     Field[] fields = clazz.getDeclaredFields(); 
     for (Field field : fields) { 

      String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected"); 
      message = message + " " + field.getType().getSimpleName(); 
      message = message + " " + field.getName(); 

      System.out.println(message); 
     } 
    } 
}; 

public void displayAnonymousInnerClass() { 
    anonymousInnerClass.printAboutme(); 
} 

public void displayStaticInnerClass() { 
    NestedStaticClass staticInnerClass = new NestedStaticClass(); 
    staticInnerClass.printAboutMe(); 
} 

public void displayInnerClass() { 
    InnerClass innerClass = new InnerClass(); 
    innerClass.printAboutMe(); 
} 

public void displayMethodInnerClass(){ 

    class MethodInnerClass { 

     private String sampleField = "Method Inner Class"; 
     public void printAboutMe() { 
      System.out.println("MethodInnerClass.printAboutMe........."); 
      Class clazz = this.getClass(); 

      Field[] fields = clazz.getDeclaredFields(); 
      for (Field field : fields) { 

       String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected"); 
       message = message + " " + field.getType().getSimpleName(); 
       message = message + " " + field.getName(); 

       System.out.println(message); 
      } 
     } 
    } 

    MethodInnerClass methodInnerClass = new MethodInnerClass(); 
    methodInnerClass.printAboutMe(); 
} 

class InnerClass { 
    private String sampleField = "Inner Class"; 
    public void printAboutMe() { 
     System.out.println("InnerClass.printAboutMe........."); 
     Class clazz = this.getClass(); 

     Field[] fields = clazz.getDeclaredFields(); 
     for (Field field : fields) { 

      String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected"); 
      message = message + " " + field.getType().getSimpleName(); 
      message = message + " " + field.getName(); 

      System.out.println(message); 
     } 
    } 
} 


abstract class AnonymousInnerClass { 
    protected String sampleField = "Anonymous Inner Class"; 
    protected abstract void printAboutme(); 
} 

static class NestedStaticClass { 
    private String sampleField = "NestedStaticClass"; 
    public void printAboutMe() { 
     System.out.println("NestedStaticClass.printAboutMe........."); 
     Class clazz = this.getClass(); 

     Field[] fields = clazz.getDeclaredFields(); 
     for (Field field : fields) { 

      String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected"); 
      message = message + " " + field.getType().getSimpleName(); 
      message = message + " " + field.getName(); 

      System.out.println(message); 
     } 
    } 
} 

}

trong ví dụ này có so sánh tất cả các loại phi lớp lồng nhau tĩnh với class.Now lồng tĩnh nếu bạn chạy phương pháp hiển thị của lớp Outer cho mỗi lớp lồng nhau, bạn sẽ thấy đầu ra của mỗi lớp inAbout lồng nhau() phương pháp, trong đó có một số mã phản ánh để in tất cả các biến thành viên của các lớp lồng nhau.

Bạn sẽ thấy đối với các lớp không lồng nhau có một biến thành viên khác ngoài chuỗi biến được khai báo trong mã, chỉ xuất hiện vào thời gian chạy. Ví dụ:

nếu chúng tôi thực thi mã sau cho InnerClass. : -

public class NestedClassesDemo { 

public static void main(String[] args) { 
    OuterClass outerClass = new OuterClass(); 
    outerClass.displayInnerClass(); 
} 

}

đầu ra là như thế này: -

InnerClass.printAboutMe......... 
private String sampleField 
protected OuterClass this$0 

Note có thành viên bí ẩn biến $ này 0 của lớp loại kèm theo (lớp Outer).

Bây giờ bạn đã rõ ràng rằng lớp bên trong giữ tham chiếu đến lớp ngoài. Kịch bản hình ảnh nơi bạn chuyển tham chiếu lớp bên trong đến lớp ngoài thế giới khác và sau đó tham chiếu không bao giờ được phát hành đến lượt OuterClass cũng được tham chiếu, do đó bị rò rỉ.

Vì vậy, điều này làm cho việc sử dụng các lớp bên trong trở nên tồi tệ nếu không được sử dụng prpperly.

Không có trường hợp như vậy với các lớp bên trong tĩnh. Vui lòng chạy tất cả các phương thức hiển thị. Ngoài ra, nếu có bất kỳ vấn đề nào trong mã, vui lòng chỉ ra.

+1

'Tĩnh bên trong' là một [mâu thuẫn về mặt] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3) và 'không tĩnh lồng nhau 'có thể được thay thế bằng' bên trong '. – EJP

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