在java中将接口类型(不实现类类型)作为参数传递
Posted
技术标签:
【中文标题】在java中将接口类型(不实现类类型)作为参数传递【英文标题】:Passing interface type (not implementing class type) as argument in java 【发布时间】:2013-04-09 23:48:08 【问题描述】:我正在开发一个“服务提供商”(与 Google 果汁非常相似)。 它的工作是将任意的 class_1 或接口映射到 *class_2*,可以被实例化并且要么实现 class_1(如果 class_1 是 接口)或者是/扩展 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:是的——google了很多,几乎没有找到。
UPD.: 谢谢大家的时间。 也许关于这一切的更多话: 目标是开发机制(ServiceProvider 类),这将帮助我避免应用程序中的紧密耦合、硬依赖。 因此,我开发/采用了以下理念: “如果你想交付一个‘单元’(可重用软件)——声明所有公共接口; 实施是你的私事,我们根本不关心; 如果有人想使用您的设备,他们应该通过以下方式向服务提供商提出请求 1. 在启动时他们使用 sp.map(IYuorInterface.class, TheClassImplementingIt.class); 2. IYuorInterface obj = sp.getService(IYuorInterface.class); 您有责任使 TheClassImplementingIt 类“可实例化”(构造函数、安全性、类不是抽象的等);如果不是 - 获得运行时异常是完全可以的。
有什么好处?
这很明显——在任何给定时间,任何其他开发人员都可以使用 ServiceProvider 重新实现 IYuorInterface 映射它,然后所有应用程序都将使用它,而无需更改一行代码。 (最简单的情况——单元测试)
所以我的观点/问题是:map() 方法中的第二个参数必须是 Class 类型,它代表一个类,而不是接口,它应该与第一个参数“分配兼容”。
换句话说,当我做 map(ISomeIterface.class, Something.class); Something 的 object(实例)应该可以这样使用:
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对象代表类和接口,在编译时无法区分是真正的类还是接口..
但无论如何——谢谢大家。
【问题讨论】:
您已经声明了 map() 以便第二个参数是实现或扩展第一个参数的类。 InstantiationException 表明创建实例时出现问题(例如,没有空构造函数)。您应该提供 getService()、IParent 和堆栈跟踪的来源。 我认为你在这方面不走运:有时,编译器不可能知道第二个参数的确切值,例如sp.map(IParent.class, someMethodThatReturnsClassDerivedFromIParent());
将编译,但直到运行时才知道返回值。我认为在运行时检查第二个参数是最好的选择。
我不明白。如果实现是您的业务,为什么客户端必须提供实现类?
【参考方案1】:
您可以使用
找出一个类是否是一个具体的、可实例化的类public boolean isConcrete(Class<?> input)
if (input.isInterface())
return false;
if (Modifier.isAbstract(input.getModifiers()))
return false;
return true;
【讨论】:
那是运行时; OP想要编译时“(关键是要得到编译时错误。我已经知道如何在运行时检查这个)” @TheCat 是运行时检查,我 99% 确信他已经知道这一点。【参考方案2】:据我所知,没有办法在编译时检查 Class
对象是否代表可实例化的类。
即使是类,它也可能是抽象的,也可能缺少无参数构造函数。
作为替代方案,我建议您使用工厂对象而不是类本身。
【讨论】:
【参考方案3】:如果你可以传递一个工厂而不是第二个参数呢?
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();
【讨论】:
以上是关于在java中将接口类型(不实现类类型)作为参数传递的主要内容,如果未能解决你的问题,请参考以下文章