Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 动态加载依附于接口的类_Java_Reflection_Interface - Fatal编程技术网

Java 动态加载依附于接口的类

Java 动态加载依附于接口的类,java,reflection,interface,Java,Reflection,Interface,我有几个类实现了两个接口。它们都实现了BaseInterface和其他一些特定于它们的接口 我希望能够使用下面的loadClass方法实例化.properties文件中引用的类,并调用它们都包含的公共方法(因为它们实现了BaseInterface) 我得到以下例外情况: Exception in thread "main" java.lang.ClassCastException: SpecificClass cannot be cast to BaseInterface at LoadClas

我有几个类实现了两个接口。它们都实现了BaseInterface和其他一些特定于它们的接口

我希望能够使用下面的loadClass方法实例化.properties文件中引用的类,并调用它们都包含的公共方法(因为它们实现了BaseInterface)

我得到以下例外情况:

Exception in thread "main" java.lang.ClassCastException:
SpecificClass cannot be cast to BaseInterface
at LoadClass.loadClass
有没有办法解决这个问题


非常感谢Danny,如果您将代码替换为下面的代码,它将正常工作。我怀疑
PropertiesLoader
正在做一些不应该做的事情

    Class<?> theClass;
    // Load the class.
    theClass = Class.forName("SpecificClass");
    // Create an instance of the class.
    C theInstance = (C) theClass.newInstance();


   BaseInterface base =  loadClass();//There is no problem in casting
Class类;
//加载该类。
类=Class.forName(“SpecificClass”);
//创建类的实例。
实例=(C)类.newInstance();
BaseInterface base=loadClass()//铸造没有问题

Java程序通常由系统类加载器加载。.properties文件中引用的类由用户定义的类加载器加载。由不同类加载器加载的类被认为是不同的,即使它们具有相同的名称并且是从相同的类文件加载的。在您的情况下,system classloader加载的接口BaseInterface与 属性加载器。
为了解决这个问题,PropertiesLoader应该将BaseInterface的加载委托给系统类加载器。典型的方法是使用系统类加载器作为PropertiesLoader的父类加载器。

Java的服务提供者接口(SPI)库允许您根据公共无参数构造函数实现的接口动态加载类,这一切都是通过使用
META-INF/services
完成的

首先,您需要
界面

package com.example;

public interface SomeService {

    String getServiceId();

    String getDisplayName();
}
然后,当您需要它们时,可以使用Java的类加载它们,该类实现了
Iterable

ServiceLoader<SomeService> loader = ServiceLoader.load(SomeService.class);
for (SomeService serv : loader) {
    System.out.println(serv.getDisplayName());
}
注意,这个类需要一个默认的无参数构造函数,这不是可选的

通过在类路径中(例如在jar的根目录中)的
META-INF/services
中创建一个具有以下属性的文件,可以向类加载器注册它:

  • 文件名是接口的完全限定类名,在本例中为
    com.example.SomeService
  • 该文件包含一个以换行符分隔的实现列表,因此对于示例实现,它将包含一行:
    com.acme.SomeImplementation

  • 好了,就这样。你如何构建你的项目将决定你把
    META-INF/services
    东西放在哪里。Maven、Ant等都有办法处理这个问题。如果在将这些文件添加到构建中时遇到任何问题,我建议您再问一个关于特定构建过程的问题。

    您应该看看Java SPI库以及如何使用
    META-INF/services
    。它几乎完成了你想做的所有事情,而且使用起来非常简单。我会马上发布一个示例课程。太棒了-非常感谢!感谢其他回答者提供的有用提示:)。
    package com.example;
    
    public interface SomeService {
    
        String getServiceId();
    
        String getDisplayName();
    }
    
    ServiceLoader<SomeService> loader = ServiceLoader.load(SomeService.class);
    for (SomeService serv : loader) {
        System.out.println(serv.getDisplayName());
    }
    
    package com.acme;
    
    public class SomeImplementation implements SomeService {
    
        // ...
    
        public SomeImplementation() { ... }
    
        // ...
    }