我正在尝试使用Class.forName,而我的Intellij正在抛出编译错误。我的IntelliJ以红色突出显示“theResponse”(在testMethod中)并给出了这个错误:
cannot find symbol symbol : method
以下是我正在使用的代码(和测试)......
package http.response;
public class TestClass {
public TestClass() {
PublicRoute publicRoute = new PublicRoute();
}
public String testMethod() throws ClassNotFoundException {
Class c = Class.forName("http.response.PublicRoute");
return c.theResponse("hi");
}
}
package http.response;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class TestClassTest {
@Test
public void test() throws ClassNotFoundException {
TestClass testClass = new TestClass();
assertEquals("public", testClass.testMethod());
}
}
更新:我试图做的是“多态”调用来自HashMap中返回作为String 的类的响应。我该怎么做?我(松散地)遵循这个例子但我完全不了解它(http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism)。这是我正在尝试做的简化版本。希望这是有道理的。
package http.response;
import java.util.HashMap;
public class TestClass {
HashMap map;
public TestClass(HashMap map) {
this.map = map;
}
public String testMethod(String lookupValue) throws ClassNotFoundException {
String className = map.get(lookupValue);
Class c = Class.forName("http.response." + className);
return c.theResponse();
}
}
答案 0 :(得分:6)
Class.forName()
返回java.lang.Class
类型的对象。从its Javadoc可以看到java.lang.Class
没有方法theResponse
。
听起来你真正想要做的是构造PublicRoute
类的实例,并在实例上调用该方法。但是你已经构建了这样一个实例:它是你在构造函数中创建的publicRoute
变量。为什么不直接使用该对象呢?
编辑:啊,我知道你要做的是什么。你基本上想要一种Service Locator模式的形式。
创建一个界面,如下所示:
public interface ResponseProvider {
String theResponse();
}
然后让所有类实现该接口:
public class PublicRoute implements ResponseProvider {
@Override
public String theResponse() {
// do whatever
}
}
然后,当您加载Class<?>
时,您可以使用asSubclass()
方法将Class<?>
转换为Class<? extends ResponseProvider>
- 然后newInstance()
将提供你支持一个ResponseProvider
对象,你可以调用theResponse()
,如下所示:
String className = ...;
Class<?> klass = Class.forName(className);
Class<? extends ResponseProvider> responseProviderClass
= klass.asSubclass(ResponseProvider.class);
ResponseProvider responseProvider = responseProviderClass.newInstance();
return responseProvider.theResponse();
但是不要手动执行此操作 - 而是使用专为此目的而设计的java.util.ServiceLoader
类。您创建了一个特殊的META-INF/services/com.my.package.ResponseProvider
文件,其中包含实现该接口的所有可能类的列表,然后ServiceLoader
可以为您提供每个类的实例。
但是......考虑不要这样做。使用Dependency Injection可以更好地解决使用服务定位器模式可以解决的问题类型(另请参阅my answer to another question about Dependency Injection)。例如,Guice DI框架提供了一个名为multibindings的功能,它看起来就像您需要的那样。
答案 1 :(得分:2)
如果theResponse()
属于http.response.PublicRoute
,那么它应该是
Class c = Class.forName("http.response.PublicRoute");
return ((PublicRoute) c.newInstance()).theResponse("hi");
但是,因为你可以使用构造函数作为
,所以真的不需要Class.forName()
return new PublicRoute().theResponse("hi");
答案 2 :(得分:2)
班级Class
没有名为theResponse
的方法。从其他代码中看,你看起来不应该使用反射;你已经静态地引用了PublicRoute
类,所以没有必要动态加载它。
我想你只想写下这个:
return PublicRoute.theResponse("hi");
或者这个:
return new PublicRoute().theResponse("hi");
(取决于theResponse
是静态方法还是实例方法)。
答案 3 :(得分:1)
让我看看我是否理解你要做的事情。你有一个hashmap,它将包含你要尝试调用theResponse(String response)
方法的类列表,对吧?我假设你不会知道将被放入hashmap的String,对吧?
其他人是正确的,你不能这样做:
Class c = Class.forName("http.response.PublicRoute");
c.theResponse("hi"); // errors because c has no knowledge of theResponse()
你需要将c转换为http.response.PublicRoute
,但随后@Ravi Thapliyal指出,你将不再需要Class.forName
了!你有一个名称的哈希映射,可能是任何东西,所以这将无法正常工作。
如果我正确地理解你做你需要的东西,你需要使用反射来尝试实例化类然后调用它上面的方法。
假设theResponse
方法是一个公共非静态方法并且只有一个参数,这就是你的方法。
// Declare the parameter type
Class[] paramString = new Class[1];
paramString[0] = String.class;
String className = map.get(lookupValue);
// Instance the class
Class cls = Class.forName("http.response." + className);
Object obj = cls.newInstance();
// Call the method and pass it the String parameter
method = cls.getDeclaredMethod("theResponse", paramString);
method.invoke(obj, new String("hi"));
当然,您需要处理异常,但是您将使用hashmap的循环包围上述代码。
我希望这有帮助!