Java 从枚举中的类初始化新对象
我有一个名为插件的枚举:Java 从枚举中的类初始化新对象,java,enums,Java,Enums,我有一个名为插件的枚举: public enum Plugins { ROTATING_LINE (plugin.rotatingline.RotatingLine.class), SNOW_SYSTEM (plugin.snow.SnowSystem.class); private Class<?> c; private Plugins (Class<?> c) { this.c = c; } pu
public enum Plugins {
ROTATING_LINE (plugin.rotatingline.RotatingLine.class),
SNOW_SYSTEM (plugin.snow.SnowSystem.class);
private Class<?> c;
private Plugins (Class<?> c) {
this.c = c;
}
public Class<?> getClassObject() {
return c;
}
}
有没有办法用类似的方法来实现这一点?我想这样做的原因是创建一个类列表,当我启动应用程序时,这些类应该添加到列表插件中。首先,您需要所有类来实现某种接口:
public interface Plugin {
public doSomething();
}
那你就可以了
Class clazz = getClassObject();
Plugin plugin = clazz.newInstance();
... add to a list where you can use later ...
关于加载插件,您可以在enum
中声明所有插件。。。或者您可以在配置.xml
或.properties
(例如)中声明它们,这将为您提供更大的灵活性:
public void loadPlugins(){
List<Plugin> plugins = new ArrayList<Plugin>();
... load plugin names from config file ...
for(String pluginClass : pluginsConfigList)
plugins.add(Class.forName(pluginClass).newInstance());
}
public void loadPlugins(){
List plugins=new ArrayList();
…从配置文件加载插件名称。。。
用于(字符串pluginClass:pluginsConfigList)
add(Class.forName(pluginClass.newInstance());
}
当然,您将需要一些基本的异常处理,等等-这段代码是根据我记得的操作匆忙编写的(:是的,您可以使用反射来完成。事实上,我们在我们的项目中的枚举中做的几乎完全相同。它工作得很好,尽管我对该解决方案创建的所有直接依赖关系不是100%满意。通过Spring等方式使用DI可能更好,但这并没有让我感到足够的困扰,无法实际使用解决方案 如果类有一个默认构造函数,只需调用
c.newInstance()
。如果没有,问题就要复杂一点——处理这个问题
当然,一旦你有了对象,你就需要对它们做些什么。标准的方法是让所有涉及的类实现同一个接口,然后你可以将对象向下转换到该接口,并对它们调用接口方法。(当然,在生产代码中,您需要捕获并处理所有可能出现的运行时异常,例如
实例化异常
,非法访问异常
和类卡斯特异常
)由于您正在迭代插件,我想所有插件的构造函数都有相同数量和类型的参数。(我不理解您的插件。添加(…)
。)
无论如何,如果您想使用enum,我将执行以下操作,使用特定于常量的方法实现,而不是类型tokens/reflection:
public enum PluginTypes {
ROTATING_LINE { Plugin create(int x, int y){
return new plugin.rotatingline.RotatingLine(x,y);} },
SNOW_SYSTEM { Plugin create(int x, int y){
return new plugin.snow.SnowSystem(x,y);} };
abstract Plugin create(int x, int y);
}
public interface Plugin {
//...
}
然后,您的循环将如下所示:
for (Plugins plugins : Plugins.values()) {
Class<?> c = plugins.getClassObject();
pluginList.add(new c(400, 400));
}
List<Plugin> plugins = new ArrayList<Plugin>();
for (PluginTypes pt : PluginTypes.values()) {
plugins.add(pt.create(400, 400));
}
List plugins=new ArrayList();
for(PluginTypes pt:PluginTypes.values()){
plugins.add(pt.create(400400));
}
另一方面,如果你知道你的插件实现类,为什么不直接使用它们而不是通过PluginTypes Enum来使用它们呢?你的第二个代码片段中有一个冲突,这让我有点困惑…变量
plugins
既用于Enum常量,也作为列表出现。所以我假设这一点,但你是应该发布代码片段,这些代码片段在将来实际工作
因此,是的,有一种方法可以满足您的需求:
for (Plugins plugins : Plugins.values()) {
Class<?> c = plugins.getClassObject();
pluginsList.add(c.getConstructor(Integer.TYPE, Integer.TYPE).newInstance(400, 400));
}
for(插件插件:Plugins.values()){
c类=plugins.getClassObject();
add(c.getConstructor(Integer.TYPE,Integer.TYPE).newInstance(400400));
}
另外,我建议您看看,这是一个非常酷的工具,可以从类路径动态加载服务。要创建类的实例,您可以按照@Peter的答案,并保留对我建议的对象的引用
EnumMap-map=新的EnumMap(Plugins.class);
for(插件插件:Plugins.values()){
c类=plugins.getClassObject();
put(插件,c.newInstance());
}
为插件创建一个接口
public interface Plugin{
setShapeType();
setX();
setY();
...
}
在枚举上创建创建插件实例的方法
public enum Plugins {
ROTATING_LINE (plugin.rotatingline.RotatingLine.class),
SNOW_SYSTEM (plugin.snow.SnowSystem.class);
private Class<? extends Plugin> c;
private Plugins (Class<? extends Plugin> c) {
this.c = c;
}
// This acts as a constructor that takes args, I am assuming the args you need
public Class<? extends Plugin> createInstance(String shapeType,int x, int y) {
Plugin plugin = c.newInstance();
plugin.setShapeType(shapeType);
plugin.setX(x);
plugin.setY(y);
return plugin;
}
}
公共枚举插件{
旋转线(plugin.rotatingline.rotatingline.class),
SNOW_系统(plugin.SNOW.SnowSystem.class);
在这种情况下,私人课程的枚举将使你的生活更加困难
在过去,我是这样解决这个问题的:
class PluginFactory<T extends Plugin> {
private Class<T> clazz;
PluginFactory(Class<T> clazz) {
this.clazz = clazz;
}
T newInstance() {
return clazz.newInstance();
}
final static PluginFactory<SnowSystem> SNOW_SYSTEM_FACTORY =
new PluginFactory(SnowSystem.class);
...
// should really use a list and a wilcard generic bounded by Plugin, but it's
// too verbose for me for the purposes of this answer
final static PluginFactory[] FACTORIES = {SNOW_SYSTEM_FACTORY, ...};
public static void main(String[] args) {
Plugin[] arr = new Plugin[FACTORIES.length];
for (int i = 0; i < arr.length; i++) {
arr[i] = FACTORIES[i].newInstance();
}
// more usefully though
SnowSystem ss = SNOW_SYSTEM_FACTORY.newInstance();
ss.setValue(123);
}
}
类插件工厂{
私人课堂;
插件工厂(clazz类){
this.clazz=clazz;
}
T newInstance(){
返回clazz.newInstance();
}
最终静态插件工厂雪地系统工厂=
新插件工厂(SnowSystem.class);
...
//确实应该使用一个列表和一个由插件绑定的wilcard泛型,但它是
//就我的回答而言,太冗长了
最终静态插件工厂[]工厂={SNOW_系统工厂,…};
公共静态void main(字符串[]args){
Plugin[]arr=新插件[FACTORIES.length];
对于(int i=0;i
另一个选项是给newInstance var args对象参数。然后使用反射来找到将这些类型作为参数的适当构造函数。如果API的用户提供了一组错误的参数(引发异常),这将是非常混乱和完全不安全的
public T新实例(对象…args){
for(构造函数c:clazz.getConstructors()){
if(isMatchingConstructor(c,args)){
返回clazz.cast(c.newInstance(args));
}
}
抛出新的NoSuchMethodException(“未找到与参数匹配的构造函数:”
+toString(args));
}
私有布尔isMatchingConstructor(构造函数c、对象…参数){
类[]参数=c.getParameterTypes();
if(parameters.length!=args.length){
返回false;
}
对于(int i=0;i
有两种方法:
使用Enum.valueOf()
静态函数,然后将其强制转换为枚举类型
Enum v = Enum.valueOf(TheEnumClass, valueInString);
class PluginFactory<T extends Plugin> {
private Class<T> clazz;
PluginFactory(Class<T> clazz) {
this.clazz = clazz;
}
T newInstance() {
return clazz.newInstance();
}
final static PluginFactory<SnowSystem> SNOW_SYSTEM_FACTORY =
new PluginFactory(SnowSystem.class);
...
// should really use a list and a wilcard generic bounded by Plugin, but it's
// too verbose for me for the purposes of this answer
final static PluginFactory[] FACTORIES = {SNOW_SYSTEM_FACTORY, ...};
public static void main(String[] args) {
Plugin[] arr = new Plugin[FACTORIES.length];
for (int i = 0; i < arr.length; i++) {
arr[i] = FACTORIES[i].newInstance();
}
// more usefully though
SnowSystem ss = SNOW_SYSTEM_FACTORY.newInstance();
ss.setValue(123);
}
}
public T newInstance(Object... args) {
for (Constructor c : clazz.getConstructors()) {
if (isMatchingConstructor(c, args)) {
return clazz.cast(c.newInstance(args));
}
}
throw new NoSuchMethodException("No matching constructor found for args: "
+ Arrays.toString(args));
}
private boolean isMatchingConstructor(Constructor c, Object... args) {
Class<?>[] parameters = c.getParameterTypes();
if (parameters.length != args.length) {
return false;
}
for (int i = 0; i < args.length; i++) {
if (!parameters[i].isAssignableFrom(args[i].getClass())) {
return false;
}
}
return true;
}
Enum v = Enum.valueOf(TheEnumClass, valueInString);
Plugins[] plugins = Plugins.class.getEnumConstants();
for (Plugins plugin: plugins) {
// use plugin.name() to get name and compare
}