[英]Call method on template argument without knowing a base class in Java
我想写一个通用算法,可以用不同的对象实例化。 这些对象来自3rdparty,并且没有通用的基类。 在C ++中,我只是将通用算法编写为模板,该模板将特定对象作为其参数。 用Java怎么做?
template <class T>
class Algorithm
{
void Run(T& worker)
{
...
auto value = workder.DoSomething(someArgs);
...
}
};
在C ++中,我不需要了解T,因为在编译过程中会检查方法的正确类型和可用性。 据我所知,在Java中,我必须有一个公共基类供所有工作人员使用,以能够对其调用方法。 这样对吗? 有没有办法在Java中做类似的事情?
我无法更改自己的3rdparty工作人员,也不想对所有工作人员(包括工作人员使用的所有类型,等等)进行自己的抽象。
编辑:
由于我只想编写一次通用算法,因此对于某些能够生成Java代码的模板语言来说,这可能是一件工作(代码模板的参数将是工作程序)?
我的解决方案:在无法更改3rdparty工作人员的情况下,我选择了Java代码生成。 我有完全相同的算法,我只需要支持所有提供相同接口(名称相同,方法名称相同的类)的不同工作程序即可。 而且在少数情况下,我必须为特定的工作人员做一些额外的代码。
更明确地说,我的“工作人员”实际上是对专有数据库的访问层,每个工作人员都使用一个数据库版本(并已生成)。 我目前的计划是使用FreeMaker之类的东西来生成多个Java源文件,每个数据库版本一个,每个文件只有不同的导入。
需要寻找的主题: 泛型
你可以声明一个像
public class Whatever<T> {
它使用允许任何引用类型的T
您无需强制性地进一步“专门化”该T。 但是,当然可以:在这种情况下,您只能在T
实例上从Object
调用方法。
如果要调用更特定的方法,则别无选择,只能以某种方式描述该规范。 因此,在您的情况下,合理的方法是至少引入一些核心接口。
换句话说:Java中没有“鸭子输入”。 您不能仅通过说具有此方法的对象来描述它。 您始终需要一个类型-类型必须是类或接口。
Java不支持鸭子类型。 它可以近似,但是您不会获得C ++所惯用的便利或强大功能。
作为选项,请考虑:
Object
-语法将很糟糕,编译器将无法帮助您进行编译检查。 switch
/ if-else-if块,类型->代码映射等。新类型将强制更改此代码。 编辑-用于代码生成和注释处理的资源:
如果您真的没有任何方法可以使用泛型正确完成,则可能需要使用反射。
class A {
public String doIt() {
return "Done it!";
}
}
class B {
public Date doIt() {
return Calendar.getInstance().getTime();
}
}
interface I {
public Object doIt();
}
class IAdapter implements I {
private final Object it;
public IAdapter(Object it) {
this.it = it;
}
@Override
public Object doIt() {
// What class it it.
Class<?> itsClass = it.getClass();
// Peek at it's methods.
for (Method m : itsClass.getMethods()) {
// Correct method name.
if (m.getName().equals("doIt")) {
// Expose the method.
m.setAccessible(true);
try {
// Call it.
return m.invoke(it);
} catch (Exception e) {
throw new RuntimeException("`doIt` method invocation failed", e);
}
}
}
// No method of that name found.
throw new RuntimeException("Object does not have a `doIt` method");
}
}
public void test() throws Exception {
System.out.println("Hello world!");
Object a = new IAdapter(new A()).doIt();
Object b = new IAdapter(new B()).doIt();
System.out.println("a = "+a+" b = "+b);
}
但是,您应该在使用反射之前,使用普通的类型安全的Java(例如,泛型)来解决此问题。
在Java中,所有Worker都必须具有DoSomething(someArgs)方法,这不一定意味着它们扩展了相同的基类,而是可以使用这种方法来实现一个Worker接口。 例如:
public interface Worker {
public Double DoSomething(String arg1, String arg2);
}
然后让不同的类实现Worker接口:
一种Worker的实现 :
public class WorkerImplA implements Worker{
@Override
public Double DoSomething(String arg1, String arg2) {
return null; // do something and return meaningful outcome
}
}
工人的另一种实现方式 :
public class WorkerImplB implements Worker{
@Override
public Double DoSomething(String arg1, String arg2) {
return null; // do something and return meaningful outcome
}
}
不同的WorkerImpl类不需要使用这种方法扩展相同的公共基类,并且从JavaSE 8开始,接口可以在其定义的任何方法中具有默认实现 。
使用这种方法, 算法类如下所示:
public class Algorithm {
private String arg1;
private String arg2;
public Algorithm(String arg1, String arg2){
this.arg1 = arg1;
this.arg2 = arg2;
}
public void Run(Worker worker){
worker.DoSomething(arg1, arg2);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.