在不知道Java中的基类的情况下对模板参数调用方法
我想写一个通用算法,可以用不同的对象实例化。这些对象来自第三方,它们没有公共基类。在C++中,我只是把泛型算法写为模板,它以特定对象作为参数。如何在Java中实现它在不知道Java中的基类的情况下对模板参数调用方法,java,templates,Java,Templates,我想写一个通用算法,可以用不同的对象实例化。这些对象来自第三方,它们没有公共基类。在C++中,我只是把泛型算法写为模板,它以特定对象作为参数。如何在Java中实现它 template <class T> class Algorithm { void Run(T& worker) { ... auto value = workder.DoSomething(someArgs); ... } }; 模板 类
template <class T>
class Algorithm
{
void Run(T& worker)
{
...
auto value = workder.DoSomething(someArgs);
...
}
};
模板
类算法
{
无效运行(T&worker)
{
...
自动值=worker.DoSomething(someArgs);
...
}
};
在C++中,我不需要知道T的任何内容,因为在编译过程中检查了正确的类型和可用性。据我所知,,
在Java中,我必须有一个通用的基类,以便我的所有工作人员都能够对它们调用方法。是这样吗?有没有办法用Java做类似的事情
我不能改变我的第三方工人,我也不想对所有工人(包括工人正在使用的所有类型,等等)进行我自己的抽象
编辑:
由于我只想编写一次泛型算法,可能它是某种能够生成Java代码的模板语言的工作(代码模板的参数将是workers)
我的解决方案:
在我无法改变第三方工作人员的情况下,我选择了Java代码生成。我有完全相同的算法,我只需要支持不同的worker,它们都提供相同的接口(具有相同名称的类、相同方法名称等)。在少数情况下,我必须为特定的工作人员编写一些额外的代码
更清楚地说,我的“worker”实际上是一个专有数据库的访问层,每个worker对应一个数据库版本(它们是生成的)。
我目前的计划是使用FreeMaker之类的工具来生成多个Java源文件,每个DB版本一个,只有不同的导入 要为您研究的主题: 您可以像这样声明一个类
public class Whatever<T> {
公共类{
它使用允许任何引用类型的T
。您不需要强制进一步“专门化”该T。但当然:在这种情况下,您只能在T
的实例上从Object
调用方法
如果你想调用一个更具体的方法,那么除了以某种方式描述该规范之外,没有其他方法了。因此,在你的例子中,合理的方法是至少引入一些核心接口
P>爪哇:没有一个“鸭子打字”,你不能只说有这个或那个方法,你总是需要一个类型,它必须是一个类或者一个接口。在java中不支持C++类型的鸭子打字。 作为备选方案,考虑:
- 完全反射+使用
-语法将非常糟糕,编译器不会帮助您进行编译检查对象
- 支持一组预先已知的类型,并使用某种静态调度,例如一个大的
/if-else-if块、一个类型->代码映射等。新类型将强制更改此代码开关
- 在注释处理过程中完成的代码生成-您可以自动执行上述静态分派方法,或者可以为实现公共接口的每个受支持类型创建包装器类型。在编译过程中需要知道这些类型,新类型需要重新编译
- 作者@sockeqwe
- ,一个干净的Square代码生成工具
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);
}
A类{
公共字符串doIt(){
返回“完成!”;
}
}
B类{
公开日期doIt(){
返回Calendar.getInstance().getTime();
}
}
接口I{
公共对象doIt();
}
类IAdapter实现了I{
私人的最终目标是它;
公共IAdapter(对象it){
this.it=it;
}
@凌驾
公共对象doIt(){
//这是什么课。
Class itsClass=it.getClass();
//看看它的方法。
对于(方法m:itsClass.getMethods()){
//正确的方法名。
if(m.getName().equals(“doIt”)){
//公开该方法。
m、 setAccessible(true);
试一试{
//叫它。
返回m.invoke(it);
}捕获(例外e){
抛出新的RuntimeException(“`doIt`方法调用失败”,e);
}
}
}
//找不到该名称的方法。
抛出新的RuntimeException(“对象没有'doIt'方法”);
}
}
public void test()引发异常{
System.out.println(“你好,世界!”);
对象a=new-IAdapter(new a()).doIt();
对象b=newIAdapter(new b()).doIt();
System.out.println(“a=“+a+”b=“+b”);
}
但是,在使用反射之前,您应该尽一切努力使用普通的类型安全Java(如泛型)来解决这个问题。在Java中,您的所有工作人员都必须有一个DoSomething方法(someArgs),这并不一定意味着它们扩展了相同的基类,相反,它们可以用这样的方法实现一个接口Worker。例如:
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);
}
public interface Worker {
public Double DoSomething(String arg1, String arg2);
}
然后让不同的类实现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
}
}
工人的另一种实施方式:
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);
}
}
也许这是一个糟糕的设计,你对类型一无所知?所以,据你所知,他们可能会通过一个测试