Java Class.forName无法编译。出现“cannot find symbol symbol : method”的错误提示。

4

我正在尝试使用Class.forName,但我的Intellij会抛出编译错误。我的IntelliJ在testMethod中将“theResponse”用红色标记,并给出以下错误:

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());
  }
}

更新: 我想要做的是从哈希表返回的类 作为字符串 “多态地”调用 theResponse。我应该怎么做呢?我(宽泛地)遵循这个示例,但我并没有完全理解它 (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();
  }

}
4个回答

6

Class.forName()会返回一个java.lang.Class类型的对象。正如您从Javadoc中看到的那样,java.lang.Class没有theResponse方法。

听起来你实际上想做的是构建PublicRoute类的实例,并调用该实例的方法。但是你已经构建了这样一个实例:在你的构造函数中创建的publicRoute变量。为什么不直接使用那个对象呢?


编辑:啊,我明白你想做什么了。你基本上想要一种服务定位器模式的形式。

创建一个接口,像这样:

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可以为你提供每个类的实例。
但是…考虑不要这样做。使用依赖注入(见依赖注入有关依赖注入的另一个问题的我的答案),通常可以更好地解决使用服务定位器模式可以解决的问题。例如,Guice DI框架提供了一个名为multibindings的功能,看起来正是你需要的。

谢谢您的回复!我添加了一个更新,说明我想要做什么。我想动态调用一个类。希望有人能帮忙。 - Kelly
@Kelly:啊,我现在明白了——感谢你澄清你的问题。我扩展了我的答案,现在有意义了吗? - Daniel Pryden
嗨,丹尼尔!再次感谢你的帮助!我从你的帖子中学到了很多。 - Kelly

2
Class没有名为theResponse的方法。从您代码的其余部分来看,这里不应该使用反射;您已经在静态地引用PublicRoute类,因此没有必要动态加载它。
我认为您只需要写下面这行代码:
return PublicRoute.theResponse("hi");

或者这样:
return new PublicRoute().theResponse("hi");

(根据theResponse是静态方法还是实例方法而定。)

谢谢您的回复!我添加了更多细节来说明我想要做什么。 - Kelly

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");

谢谢您的回复!我添加了我试图做的更多细节。 - Kelly

1
让我看看你试图做什么。你有一个哈希映射表,其中包含你将尝试调用theResponse(String response)方法的类列表,对吗?我猜你也不知道会把哪个字符串放入哈希映射表中,对吗?
其他人说得没错,你不能只是这样做:
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方法是公共非静态方法,并且只有1个参数。
// 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"));

当然,您需要处理异常,但您需要将上述代码用于哈希映射的循环中。
希望这可以帮助您!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接