Java 动态加载依附于接口的类
我有几个类实现了两个接口。它们都实现了BaseInterface和其他一些特定于它们的接口 我希望能够使用下面的loadClass方法实例化.properties文件中引用的类,并调用它们都包含的公共方法(因为它们实现了BaseInterface) 我得到以下例外情况: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
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() { ... }
// ...
}