Xác định xem một Lớp có triển khai một giao diện trong Java hay không


92

Tôi có một Classđối tượng. Tôi muốn xác định xem kiểu mà Classđối tượng đại diện có triển khai một giao diện cụ thể hay không. Tôi đã tự hỏi làm thế nào điều này có thể đạt được?

Tôi có mã sau đây. Về cơ bản những gì nó làm là nhận một mảng tất cả các lớp trong một gói được chỉ định. Sau đó, tôi muốn đi qua mảng và thêm các đối tượng Lớp triển khai giao diện vào bản đồ của tôi. Vấn đề là isInstance()lấy một đối tượng làm tham số. Tôi không thể khởi tạo giao diện. Vì vậy, tôi hơi thua thiệt với điều này. Có ý kiến ​​gì không?

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(clazz.isInstance(/*Some object*/)) //Need something in this if statement
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}

Câu trả lời:


215

Bạn nên sử dụng isAssignableFrom:

if (YourInterface.class.isAssignableFrom(clazz)) {
    ...
}

Điều này hoạt động nếu dự án giống nhau. Nhưng nếu bạn sao chép mã giao diện 1: 1, tạo một dự án và jar mới, sau đó cố gắng tải jar đó làm plugin, cuộc gọi sẽ trả về false. So sánh theo tên thì "tác phẩm", như Roddy đã đăng. Nhưng tôi không biết làm thế nào để kiểm tra điều này theo cách Java cuối cùng xác minh tính tương thích. Bằng tên là một cách tiếp cận bẩn thỉu. Của bạn, tất nhiên là tốt, nếu dự án giống nhau. ................ CÓ THỂ Tôi đang làm sai: Tôi tạo một phiên bản URLClassLoader cho tệp plugin và tải nó như vậy. Có lẽ tôi nên thử một trình tải lớp khác.
Chủ tịch Dreamspace

4
Bạn đang gặp sự cố khi tải lớp học. Nếu bạn tải cùng một lớp hai lần với các trình tải lớp khác nhau, hai Classphiên bản sẽ không tương thích. Bạn có thể thấy các lỗi như java.lang.ClassCastException: com.my.CustomClass cannot be cast to com.my.CustomClasshoặc một cái gì đó tương tự không thể giải thích được.
Flavio

Bây giờ tôi đã thử nhiều cách tiếp cận khác nhau và cuối cùng, hóa ra vấn đề chính mà tôi gặp phải là: Mặc dù giao diện trong plugin và dự án chính của tôi giống hệt nhau nhưng chúng không ở cùng một nơi, vì vậy không gian tên / địa chỉ là một cái khác. Btw., Tôi hiện đang sử dụng: myClassLoader = new URLClassLoader(new URL[] { candidateFile.toURI().toURL() }, LoadedPlugin.class.getClassLoader());classToLoad = Class.forName("com.blablabla.plugin.Main", true, myClassLoader);instance = (MyIntf) classToLoad.newInstance();Hoạt động như một sự quyến rũ.
Chủ tịch Dreamspace

17

bạn có thể sử dụng chức năng dưới đây để nhận tất cả các giao diện đã triển khai

Class[] intfs = clazz.getInterfaces();

10

Bạn có thể sử dụng class.getInterfaces()và sau đó kiểm tra xem lớp giao diện có trong đó không.

Class someInterface; // the interface you want to check for 
Class x; // 
Class[] interfaces = x.getInterfaces();

for (Class i : interfaces) {
    if (i.toString().equals(someInterface.toString()) {
        // if this is true, the class implements the interface you're looking for
    }
}

Cách tiếp cận này về mặt kỹ thuật sẽ hiệu quả, nhưng cách tiếp cận đơn giản và sạch sẽ hơn nhiều được sử dụng isAssignableFromnhư Flavio đã đề cập.
jwj

Vâng, đó là sự thật, mặc dù câu trả lời của bạn đã được tán thành nhiều lần và tôi nghĩ sẽ hữu ích nếu thêm một số ngữ cảnh. Mặc dù việc sử dụng isAssignableFromcó lẽ là thích hợp hơn, nhưng có thể có những trường hợp bạn cần quét danh sách các giao diện mà một lớp triển khai bằng cách xem tên.
jwj

Điều này thực sự không hoạt động, getInterfaces () chỉ hoạt động nếu lớp triển khai trực tiếp giao diện, nếu lớp cha triển khai giao diện hoặc một siêu giao diện mở rộng nó, giao diện đó sẽ không được trả về bởi getInterfaces (). Bạn cần duyệt qua cây của tất cả các siêu lớp và giao diện để có được tất cả các giao diện mà lớp đó thực hiện.
James Roper

Đó không phải là câu hỏi.
Roddy of the Frozen Peas,

1

Bạn cũng có thể đặt trường hợp thêm ".class"

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(Interface.class.isAssignableFrom(clazz))
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}

2
Đối với bất kỳ ai xem xét cách tiếp cận này, vui lòng xem xét câu trả lời của Flavio. Lưu ý rằng mã trong ví dụ này thực hiện một số điều có thể không có ý nghĩa ngay lập tức: ClassUtilskhông phải là một phần của Java (nó nằm trong Guava hoặc Spring và các khung công tác khác), thuật ngữ Interfacenhư được sử dụng ở trên có nghĩa là để chỉ một giao diện cụ thể đang được thử nghiệm ( tức là, nó không phải là một từ khóa Java trong ngữ cảnh này), và mục đích của retValkhông được giải thích hoặc đề cập ở bất cứ đâu.
jwj
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.