我正在开发一个“服务提供商”(非常类似于Google果汁)。 它的工作是将任意class_1或接口映射到* class_2 *,可以实例化并实现class_1(如果class_1是接口)或者是/ extends class_1(如果是class_1)不是一个界面。)
所以目前我有方法
public <T> void map(Class<T> key, Class<? extends T> service)
代码的问题是我可以将接口类型映射到接口类型,如
ServiceProvider sp = new ServiceProvider();
sp.map(IParent.class, IChild.class);
这完美编译没有错误(IChild扩展IParent)。 当然,后来,当我想:
IParent obj = sp.getService(IParent.class); //look for IParent mapping and instantiate the proper object
我收到了java.lang.InstantiationException。
所以问题是:
如何声明map()方法,以便编译器检查第二个参数是类实现或扩展第一个参数而不是接口? (重点是编译时错误。我已经知道如何在运行时检查)
感谢。 PS:是的 - 搜索了很多,几乎没有发现。
UPD: 谢谢大家的时间。 也许关于这一切的更多话语: 目标是开发机制(ServiceProvider类),它将帮助我避免在我的应用程序中紧密耦合,硬依赖。 所以我开发/采用了以下理念: “如果你想提供'单位'(可重复使用的软件) - 声明所有公共接口; 实施是您的私营企业,我们根本不关心; 如果有人想使用您的设备,他们应该从ServiceProvider请求它 1.在启动时,他们使用sp.map(IYuorInterface.class,TheClassImplementingIt.class); 2. IYuorInterface obj = sp.getService(IYuorInterface.class); 你负责使TheClassImplementingIt类'可实例化'(构造函数,安全性,类不是抽象等);如果不是 - 可以获得运行时异常。
有什么好处?
很明显 - 在任何给定时间,任何其他开发人员都可以重新实现IYuorInterface映射它与ServiceProvider,然后所有应用程序将使用它而无需更改单行代码。 (最简单的情况是需要它 - 单元测试)
所以我的观点/问题是:map()方法中的第二个参数必须是Class类型,它表示一个Class,而不是Interface,它应该与第一个参数“赋值兼容”。
换句话说,当我做map(ISomeIterface.class,Something.class)时; Something的对象(实例)应该像这样使用:
ISomeIterface obj = sp.getService(ISomeIterface.class);
//or in other words, just for example -- the Something can be used like this:
ISomeIterface obj = new Something();
这就是为什么工厂,如某些答案所暗示的那样不可接受,ServiceProvider类已经是一种“工厂”
..似乎Java的Class对象同时代表了类和接口,并且在编译时没有办法区分真正的类或接口..
但无论如何 - 感谢所有人。
答案 0 :(得分:0)
您可以使用
查明Class是否是具体的,可实例化的类public boolean isConcrete(Class<?> input)
{
if (input.isInterface())
return false;
if (Modifier.isAbstract(input.getModifiers()))
return false;
return true;
}
答案 1 :(得分:0)
据我所知,如果Class
对象代表一个可实现的类,则无法在编译时检查。
即使在类的情况下,它也可能是抽象的,或者它可能缺少一个无参数的构造函数。
作为替代方案,我建议您使用Factory对象而不是类本身。
答案 2 :(得分:0)
如果不是第二个参数,你可以改为通过工厂。
interface IInterface{
void go();
}
class IInterfaceImpl implements IInterface{
public void go(){}
}
interface Factory<T>{
T createInstance();
}
class FactoryImpl implements Factory<IInterface>{
@Override
public IInterface createInstance() {
//you need to return an instance of IInterface, which can only be a class
return new IInterfaceImpl();
}
}