Lớp bên trong trong Giao diện


97

Có thể tạo một lớp bên trong trong một giao diện không?
Nếu có thể, tại sao chúng ta lại muốn tạo một lớp bên trong như vậy vì chúng ta sẽ không tạo bất kỳ đối tượng giao diện nào?

Các lớp bên trong này có giúp ích gì trong quá trình phát triển không?

Câu trả lời:


51

Có, bạn có thể tạo cả lớp lồng nhau hoặc lớp bên trong bên trong giao diện Java (lưu ý rằng trái ngược với niềm tin phổ biến, không có cái gọi là " lớp bên trong tĩnh ": điều này đơn giản là vô nghĩa, không có gì "bên trong" và không " lớp outter "khi một lớp lồng nhau là lớp tĩnh, vì vậy nó không thể là" lớp bên trong tĩnh ").

Dù sao, các biên dịch sau đây vẫn tốt:

public interface A {
    class B {
    }
}

Tôi đã thấy nó được sử dụng để đặt một số loại "trình kiểm tra hợp đồng" trực tiếp trong định nghĩa giao diện (tốt, trong lớp được lồng trong giao diện, có thể có các phương thức tĩnh, trái ngược với chính giao diện, điều này không thể). Trông như thế này nếu tôi nhớ không nhầm.

public interface A {
    static class B {
        public static boolean verifyState( A a ) {
            return (true if object implementing class A looks to be in a valid state)
        }
    }
}

Lưu ý rằng tôi không bình luận về tính hữu ích của một thứ như vậy, tôi chỉ đơn giản trả lời câu hỏi của bạn: nó có thể được thực hiện và đây là một cách sử dụng tôi đã thấy nó.

Bây giờ tôi sẽ không bình luận về tính hữu dụng của một cấu trúc như vậy và từ tôi đã thấy: Tôi đã thấy nó, nhưng nó không phải là một cấu trúc rất phổ biến.

Cơ sở mã 200KLOC ở đây, nơi điều này xảy ra chính xác không thời gian (nhưng sau đó chúng tôi có rất nhiều thứ khác mà chúng tôi coi là các hoạt động xấu xảy ra chính xác không thời gian mà người khác sẽ thấy hoàn toàn bình thường như vậy ...).


Bạn có thể thêm một số ví dụ về cách sử dụng? Tôi đã thử nghiệm một cái gì đó tương tự cách đây một thời gian và không hiểu tôi có thể thu được gì từ việc sử dụng cấu trúc này.
La Mã

@Roman: tôi nhớ là tôi đã gặp điều này trong một số dự án (tôi sẽ thêm dự án tương đối sạch sẽ nhưng chúng không phải của tôi) nhưng tôi không biết nó có thực sự sạch hay không. Tôi đã thêm một ví dụ nhỏ trông giống như những gì tôi đã thấy nhưng một lần nữa: đây không phải mã của tôi và tôi không sử dụng cấu trúc đó vì vậy tôi không đủ điều kiện nhất để đưa ra các ví dụ hợp lệ :) IIRC lớp bên trong luôn được đặt tên, ví dụ StateChecker và các lệnh gọi sẽ luôn có dạng: A.StateChecker.check (a) hoặc tương tự như vậy.
Cú phápT3rr0r Ngày

8
Nếu bạn nói rằng “không có cái gọi là“ lớp bên trong tĩnh ”” thì câu trả lời của bạn rằng “bạn có thể tạo cả lớp lồng nhau hoặc lớp bên trong bên trong giao diện Java” về cơ bản là sai. Sử dụng định nghĩa thu hẹp của bạn, interfaces không thể có các lớp bên trong. Bạn có thể bỏ qua staticsửa đổi của một interfacelớp lồng nhau nhưng vẫn là một lớp lồng nhau, không phải lớp bên trong.
Holger

6
Câu trả lời này là sai. Các giao diện có thể có các lớp lồng nhau tĩnh nhưng không có các lớp bên trong.
Paul Boddington

1
@PaulBoddington Bạn nói đúng. Ngay cả khi loại bỏ 'static', Blớp là một lớp lồng nhau tĩnh và không phải là một lớp bên trong; giao diện được đối xử đặc biệt. Tôi không thể tìm thấy đề cập đến điều này trực tuyến, ngoại trừ trong thông số kỹ thuật: "Một lớp thành viên của giao diện là tĩnh hoàn toàn nên không bao giờ được coi là một lớp bên trong." docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Max Barraclough

109

Có, chúng ta có thể có các lớp bên trong giao diện. Một ví dụ về cách sử dụng có thể là

public interface Input
{
    public static class KeyEvent {
         public static final int KEY_DOWN = 0;
         public static final int KEY_UP = 1;
         public int type;
         public int keyCode;
         public char keyChar;
    }
    public static class TouchEvent {
         public static final int TOUCH_DOWN = 0;
         public static final int TOUCH_UP = 1;
         public static final int TOUCH_DRAGGED = 2;
         public int type;
         public int x, y;
         public int pointer;
    }
    public boolean isKeyPressed(int keyCode);
    public boolean isTouchDown(int pointer);
    public int getTouchX(int pointer);
    public int getTouchY(int pointer);
    public float getAccelX();
    public float getAccelY();
    public float getAccelZ();
    public List<KeyEvent> getKeyEvents();
    public List<TouchEvent> getTouchEvents();
}

Ở đây mã có hai lớp lồng nhau dùng để đóng gói thông tin về các đối tượng sự kiện mà sau này được sử dụng trong các định nghĩa phương thức như getKeyEvents (). Có chúng bên trong giao diện Đầu vào cải thiện sự gắn kết.


3
@Levit Chỉ tự hỏi, lớp được triển khai sẽ trông như thế nào?
trao đổi quá

1
Rất thích thấy một triển khai đang hoạt động cho cách sử dụng trên. Cảm ơn bạn.
Prakash K

45

Sử dụng hợp lệ, IMHO, là xác định các đối tượng được nhận hoặc trả về bởi các phương thức giao diện bao quanh. Cấu trúc lưu giữ dữ liệu theo mẹo. Bằng cách đó, nếu đối tượng chỉ được sử dụng cho giao diện đó, bạn có mọi thứ theo cách gắn kết hơn.

Ví dụ như:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

Nhưng dù sao thì ... vấn đề chỉ là hương vị.


34

Trích dẫn từ thông số kỹ thuật Java 7 :

Các giao diện có thể chứa các khai báo kiểu thành viên (§8.5).

Khai báo kiểu thành viên trong giao diện là hoàn toàn tĩnh và công khai. Được phép chỉ định dư thừa một trong hai hoặc cả hai từ bổ nghĩa này.

Không thể khai báo các lớp không tĩnh bên trong giao diện Java, điều này có ý nghĩa với tôi.


Cảm ơn bạn. Đây có lẽ là câu trả lời ngắn gọn nhất.
Joseph

1
Đây là câu trả lời mà tôi đang tìm kiếm .. nhưng OP hỏi một số câu hỏi .. dù sao cũng có cập nhật của tôi.
Charlie Wallace

11

Một trường hợp sử dụng thú vị là cung cấp loại triển khai mặc định cho các phương thức giao diện thông qua một lớp bên trong như được mô tả tại đây: https://stackoverflow.com/a/3442218/454667 (để khắc phục vấn đề kế thừa một lớp).


Và đây chính là lý do tại sao các lớp thành viên riêng sẽ có ý nghĩa.
Vincent

7

Nó chắc chắn là có thể, và một trường hợp mà tôi thấy nó hữu ích là khi một giao diện phải ném các ngoại lệ tùy chỉnh. Bạn giữ các ngoại lệ với giao diện được liên kết của chúng, điều mà tôi nghĩ thường gọn gàng hơn là rải rác cây nguồn của bạn với hàng đống tệp ngoại lệ tầm thường.

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}

7

Có, có thể có các định nghĩa lớp tĩnh bên trong một giao diện, nhưng có lẽ khía cạnh hữu ích nhất của tính năng này là khi sử dụng các kiểu enum (là loại lớp tĩnh đặc biệt). Ví dụ, bạn có thể có một cái gì đó như thế này:

public interface User {
    public enum Role {
        ADMIN("administrator"),
        EDITOR("editor"),
        VANILLA("regular user");

        private String description;

        private Role(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    public String getName();
    public void setName(String name);
    public Role getRole();
    public void setRole(Role role);
    ...
}


1

Có thể khi bạn muốn các cấu trúc phức tạp hơn như một số hành vi triển khai khác nhau, hãy xem xét:

public interface A {
    public void foo();

    public static class B implements A {
        @Override
        public void foo() {
            System.out.println("B foo");
        }
    }
}

Đây là giao diện của bạn và đây sẽ là người triển khai:

public class C implements A {
    @Override
    public void foo() {
        A.B b = new A.B();
        b.foo(); 
    }

    public static void main(String[] strings) {
        C c = new C();
        c.foo();
    }
}

Có thể cung cấp một số triển khai tĩnh, nhưng điều đó sẽ không gây nhầm lẫn, tôi không biết.


0

Tôi đã tìm thấy một cách sử dụng loại cấu trúc này.

  1. Bạn có thể sử dụng cấu trúc này để định nghĩa và nhóm tất cả các hằng số tĩnh cuối cùng.
  2. Vì nó là một giao diện mà bạn có thể thực hiện điều này trên một lớp.

Bạn có quyền truy cập vào tất cả các hằng số được nhóm lại; tên của lớp hoạt động như một không gian tên trong trường hợp này.


0

Bạn cũng có thể tạo các lớp tĩnh "Người trợ giúp" cho chức năng chung cho các đối tượng triển khai giao diện này:

public interface A {
    static class Helper {
        public static void commonlyUsedMethod( A a ) {
           ...
        }
    }
}

0

Tôi cần một cái ngay bây giờ. Tôi có một giao diện nơi sẽ thuận tiện để trả về một lớp duy nhất từ ​​một số phương thức của nó. Lớp này chỉ có ý nghĩa như một vùng chứa các phản hồi từ các phương thức của giao diện này.

Do đó, sẽ rất tiện lợi nếu có một định nghĩa lớp lồng nhau tĩnh, chỉ được liên kết với giao diện này, vì giao diện này phải là nơi duy nhất mà lớp vùng chứa kết quả này từng được tạo.


0

Ví dụ các đặc điểm (giao diện giống như giao diện với các phương thức được triển khai) trong Groovy. Chúng được biên dịch sang một giao diện chứa lớp bên trong, nơi tất cả các phương thức được triển khai.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.