我正在寻找一个转换器,用普通的Java代码制作反射式Java代码。我这样做是为了防止像NoClassDefFoundError
这样的异常(我想依赖于一个类,但是如果我正在使用的库没有那个依赖类,我希望Java简单地忽略代码)。
我希望这样的转换器:
初始代码:
com.foo.MyClass myClass = new com.foo.MyClass()
myClass.meth1();
转换后:
Object myClass = Class.forName("com.foo.MyClass").newInstance();
myClass.getMethods("meth1").invoke(myClass);
答案 0 :(得分:1)
您应尽量避免在Java代码中使用反射。您可以使用其他方法,例如@mwittrock建议的方法,以避免获取NoClassDefFoundError
。
您可以使用反射解决问题,但您可能会在设计中引入新问题。考虑性能成本以及反射代码的详细程度。
核心反射设施是 最初的设计 基于组件的应用程序构建器 工具......有几个 复杂的应用程序 需要反思。例子包括 类浏览器,对象检查器, 代码分析工具和解释 嵌入式系统......如果你有的话 怀疑你是否申请 它属于这些类别之一 可能不会。
Joshua Bloch,“Effective Java”,第2版。
答案 1 :(得分:1)
这可能是一种技术上可行的方法,但与其他海报一样,我建议您考虑这是否是解决问题的正确方法(并且您已经问过如何实施此解决方案而不是如何解决原始问题,所以我不能告诉你你是否走在正确的轨道上。)
您是否有兴趣选择依赖图书馆而不是强迫您的客户提供图书馆?根据您的构建系统,这并不难实现。例如,Maven允许您将依赖项指定为<scope>optional</scope>
,这允许您针对它编译代码,但不将其作为传递依赖项包含在内。
话虽如此,确实可以选择性地依赖某些图书馆,并且如果它们不可用则采取替代路线。根据我的经验,通过隐藏界面背后的细节最容易做到这一点。
作为一个例子,我有一个ProfilingAdvisor接口,可以使用AspectJ方面来分析我用自定义注释标记的方法。我有一个名为SimpleProfilingAdvisor的这个接口的基本实现,它没有外部依赖。我有一个更详细的实现,它使用Java Simon库获取更多信息,名为SimonProfilingAdvisor。
如果客户选择包含Java Simon库,他们将获得“更好”的实现。如果他们选择不这样做,则实施“基础”方法(在您的情况下可能根本不做任何事情)。
我的代码总是对接口ProfilingAdvisor进行操作,但在实例化此类型的实例变量时,我必须确定可选的Simon库是否在类路径中:
private ProfilingAdvisor advisor;
/* ... */
try {
Class.forName("org.javasimon.SimonManager");
this.advisor = new SimonProfilingAdvisor();
} catch (ClassNotFoundException classNotFoundException) {
this.advisor = new SimpleProfilingAdvisor();
}
最后一点。虽然你可以像你建议的那样使用反射来确定一个类的存在,但是在实例化之后通过对它进行反射方法访问,我无法想到你正在获得的任何东西,并且你实际上绕过了编译器的能力。您对方法名称的拼写等。
至少,您应该使用一个构建系统,该系统允许您在编译时针对库进行编译,但不一定在以后将其包含在您的发行版中(例如,Maven)。