[英]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.