首先,请阅读以下代码。
我想调用SuperClass的invoke方法,而不必将返回值强制转换为相应的类型。 问题是SuperClass实现位于一个项目中,SuperClassImpl1和2位于另一个项目中。
在运行时,它们位于不同的类加载器中,即ClassLoader 1知道SuperClass但不知道SuperclassImpl1。我有一个“SuperClassLoader”,它给ClassLoader 1一个类对象,例如SuperClassImpl2,但我只能将它用作SuperClass对象。
现在我的代码看起来像下面的代码,我必须将其转换为例如如果我知道我给invoke的方法名返回一个Map,那就是Map。
我想要的是,取决于methodName给出的方法的返回类型,invoke方法的返回类型应该相应地改变。
E.g。 invoke("getMyMap")
应该返回一张地图。请注意,我不想要这个:
Map m = invoke("getMyMap");
m.get(...);
我想要这个:
invoke("getMyMap").get(...);
有可能吗?
public abstract class SuperClass(){
public Object invoke(String methodName){
Method method = this.getClass().getDeclaredMethod(methodName);
return method.invoke(this);
}
}
public class SuperClassImpl1() extends SuperClass{
Map<String,String> myMap;
public SuperClassImpl1(){
myMap = new HashMap<String,String>();
}
public Map<String,String> getMyMap(){
return myMap;
}
}
public class SuperClassImpl2() extends SuperClass{
List<String> myList;
public SuperClassImpl2(){
myList = new ArrayList<String>();
}
public ArrayList<String> getMyList(){
return myList;
}
}
public class MainClass(){
public static void main(String[] args){
SuperClass mySuperClass1 = new SuperClassImpl1();
SuperClass mySuperClass2 = new SuperClassImpl2();
System.out.println("Something in my map: "+mySuperClass1.invoke("getMyMap").get("Some value"));
// something similar using mySuperClass2 here...
}
}
答案 0 :(得分:2)
问题在于,在invoke()的定义中,返回类型始终是一个对象。这就是事情的方式。(documentation)
如果你想使用反射,你必须在某些时候使用转换。您可以创建一个包装方法来为您进行转换,但是没有解决它。
我开始工作的方式是这样的:
System.out.println("Something in my map: "+((Map<?, ?>) mySuperClass1.invoke("getMyMap")).get("Some value"));
答案 1 :(得分:0)
您不能这样做,因为在编译时检查泛型类型,并且在运行时才知道您调用的方法的实际返回类型。
Map m = invoke("getMyMap"); // checked at compile time
return method.invoke(this); // resolved at run time
答案 2 :(得分:0)
方法的返回类型不能依赖于传递给它的String,因为类型在编译时解析,而参数只在运行时知道。
但是,您可以在类中添加参数。
public abstract class SuperClass<T> {
public T invoke(String methodName){
Method method = this.getClass().getDeclaredMethod(methodName);
return (T) method.invoke(this);
}
}
public class SuperClassImpl1() extends SuperClass<Map<String, String>> {
...
}
public class MainClass(){
public static void main(String[] args){
SuperClass<Map<String, String>> mySuperClass1 = new SuperClassImpl1();
SuperClass<ArrayList<String>> mySuperClass2 = new SuperClassImpl2();
System.out.println("Something in my map: "+mySuperClass1.invoke("getMyMap").get("Some value"));
// something similar using mySuperClass2 here...
}
}