พิจารณาว่าคลาสใช้อินเตอร์เฟสใน Java หรือไม่


92

ฉันมีClassวัตถุ ฉันต้องการตรวจสอบว่าประเภทที่Classวัตถุแสดงใช้อินเทอร์เฟซเฉพาะหรือไม่ ฉันสงสัยว่าจะทำได้อย่างไร?

ฉันมีรหัสต่อไปนี้ โดยทั่วไปสิ่งที่ทำคือรับอาร์เรย์ของคลาสทั้งหมดในแพ็คเกจที่ระบุ จากนั้นฉันต้องการดูอาร์เรย์และเพิ่มวัตถุคลาสที่ใช้อินเทอร์เฟซในแผนที่ของฉัน ปัญหาคือisInstance()ใช้วัตถุเป็นพารามิเตอร์ ฉันไม่สามารถสร้างอินเทอร์เฟซได้ ดังนั้นฉันจึงแพ้กับสิ่งนี้ ความคิดใด ๆ ?

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);
    }
}

คำตอบ:


215

คุณควรใช้isAssignableFrom:

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

วิธีนี้ใช้ได้ผลถ้าโครงการเหมือนกัน แต่ถ้าคุณคัดลอกโค้ดอินเทอร์เฟซ 1: 1 สร้างโปรเจ็กต์และ jar ใหม่จากนั้นลองโหลด jar นั้นเป็นปลั๊กอินการโทรจะส่งคืนเท็จ เปรียบเทียบตามชื่อแล้ว "ใช้ได้" เหมือนที่ Roddy โพสต์ไว้ แต่ฉันไม่รู้ว่าจะตรวจสอบสิ่งนี้ด้วยวิธีที่ Java ตรวจสอบความเข้ากันได้ในที่สุด ตามชื่อเป็นแนวทางที่สกปรก ขอแสดงความนับถือแน่นอนถ้าโครงการเหมือนกัน ................ MAYBE ฉันทำผิด: ฉันสร้างอินสแตนซ์ URLClassLoader สำหรับไฟล์ปลั๊กอินและโหลดแบบนั้น บางทีฉันควรลองใช้ตัวโหลดคลาสอื่น
Dreamspace President

4
คุณมีปัญหาในการโหลดชั้นเรียน หากคุณโหลดคลาสเดียวกันสองครั้งโดยใช้ตัวโหลดคลาสต่างกันClassอินสแตนซ์ทั้งสองจะเข้ากันไม่ได้ คุณอาจเห็นข้อผิดพลาดเช่นjava.lang.ClassCastException: com.my.CustomClass cannot be cast to com.my.CustomClassหรือบางอย่างที่อธิบายไม่ได้ในทำนองเดียวกัน
Flavio

ตอนนี้ฉันได้ลองใช้วิธีการต่างๆแล้วและในที่สุดปรากฎว่าปัญหาหลักที่ฉันมีคือ: แม้ว่าอินเทอร์เฟซในปลั๊กอินและโปรเจ็กต์หลักของฉันจะเหมือนกัน แต่ก็ไม่ได้อยู่ในที่เดียวกันดังนั้นเนมสเปซ / ที่อยู่ เป็นสิ่งที่แตกต่าง . btw ผมตอนนี้ใช้: myClassLoader = new URLClassLoader(new URL[] { candidateFile.toURI().toURL() }, LoadedPlugin.class.getClassLoader());และclassToLoad = Class.forName("com.blablabla.plugin.Main", true, myClassLoader);และinstance = (MyIntf) classToLoad.newInstance();ทำงานเช่นเสน่ห์
ประธาน Dreamspace

17

คุณสามารถใช้ฟังก์ชันด้านล่างเพื่อรับอินเทอร์เฟซที่ใช้งานทั้งหมด

Class[] intfs = clazz.getInterfaces();

10

คุณสามารถใช้class.getInterfaces()และตรวจสอบเพื่อดูว่ามีคลาสอินเทอร์เฟซอยู่ในนั้นหรือไม่

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
    }
}

วิธีนี้จะใช้ได้ผลในทางเทคนิค แต่วิธีที่ง่ายและสะอาดกว่านั้นคือการใช้isAssignableFromตามที่ Flavio กล่าวถึง
jwj

ใช่นั่นเป็นความจริงแม้ว่าคำตอบของคุณจะได้รับการโหวตมากกว่าสองสามครั้งและฉันคิดว่าการเพิ่มบริบทจะเป็นประโยชน์ ในขณะที่ใช้isAssignableFromอาจเป็นที่ต้องการ แต่อาจมีบางกรณีที่คุณต้องสแกนรายการอินเทอร์เฟซที่คลาสใช้โดยดูจากชื่อ
jwj

สิ่งนี้ใช้ไม่ได้จริง getInterfaces () จะใช้งานได้ก็ต่อเมื่อคลาสนั้นใช้อินเทอร์เฟซโดยตรงหากซูเปอร์คลาสใช้อินเทอร์เฟซหรือซูเปอร์อินเทอร์เฟซขยายอินเทอร์เฟซนั้นจะไม่ถูกส่งคืนโดย getInterfaces () คุณต้องสำรวจโครงสร้างของซุปเปอร์คลาสและอินเทอร์เฟซทั้งหมดเพื่อรับอินเทอร์เฟซทั้งหมดที่คลาสใช้
James Roper

นั่นไม่ใช่คำถามว่า
Roddy of the Frozen Peas

1

คุณยังสามารถตั้งค่าอินสแตนซ์เพิ่ม ".class"

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

2
สำหรับใครก็ตามที่กำลังมองหาแนวทางนี้โปรดพิจารณาคำตอบของ Flavio โปรดทราบว่าโค้ดในตัวอย่างนี้ทำบางสิ่งที่อาจไม่สมเหตุสมผลในทันที: ClassUtilsไม่ใช่ส่วนหนึ่งของ Java (อยู่ใน Guava หรือ Spring และเฟรมเวิร์กอื่น ๆ ) คำInterfaceที่ใช้ข้างต้นหมายถึงการอ้างถึงอินเทอร์เฟซเฉพาะที่กำลังทดสอบ ( กล่าวคือไม่ใช่คีย์เวิร์ด Java ในบริบทนี้) และวัตถุประสงค์ของการretValไม่ได้รับการอธิบายหรือกล่าวถึงที่ใดก็ได้
jwj
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.