Java 反思:使用接口初始化对象,但使用 class 名称的字符串值
Java Reflection : Initialize object using interface but using String value for class name
假设我有以下设置
一个interface
public interface TestInterface {
public void draw();
}
和两个实现
public class Square implements TestInterface {
@Override
public void draw() {
System.out.println("Square");
}
}
和
public class Circle implements TestInterface {
@Override
public void draw() {
System.out.println("Circle");
}
}
现在我可以轻松做到
TestInterface a = new Square();
a.draw();
我正确地得到 Square
。接下来,我想试试反射。
Class<?> clazz = null;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Constructor<?> constructor = null;
try {
constructor = clazz.getConstructor();
} catch (NoSuchMethodException | SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Object instance = null;
try {
instance = constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Method method = null;
try {
method = instance.getClass().getMethod(methodName);
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
method.invoke(instance);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
和 className
作为 some.package.Square
和 methodName
作为 draw
我再次得到 Square
。哪个是正确的。
问题是我的应用程序可以访问 interface
但不能访问实际的实现。因此我知道要调用哪些方法,但我还必须指定已实现的 classes 并且我不知道它们可能驻留在哪个包中。如果我只知道 class 但不是包?
有没有办法让我仍然可以使用
的初始化形式
TestInterface a = new <some_parameter>();
a.draw();
有没有办法概括它?还是我上面展示的使用反射的方法是实现类似目标的唯一方法?最后,如果我使用抽象 class 而不是接口,会有什么不同吗?
你必须知道 class 的全名。仅 class 的名称不足以将其加载到内存中并通过反射使用它。但是,您可以使用 reflections 库确定接口的实现。
也许这个讨论帖可以帮助您:How can I get a list of all the implementations of an interface programmatically in Java?
您需要通过:
@param className the fully qualified name of the desired class.
例如当您有三个 class 具有相同的名称但在不同的包中时
--package1
----Test
--package2
----Test
Main
Test
在 Main 中你有:
public static void main(String[] args) throws UnsupportedEncodingException {
Class<?> clazz = null;
try {
clazz = Class.forName("Test");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
它将调用Main级别的那个。要调用其他人,您需要传递完全合格的名称。
clazz = Class.forName("package1.Test");
clazz = Class.forName("package2.Test");
如果我只知道 class 而不知道包的名称怎么办? 所以你需要知道你想要的级别。因为正如您所知,不同的包 classes 可以具有相同的名称。那么,如果您有这个问题,您需要哪个Class。
假设我有以下设置
一个interface
public interface TestInterface {
public void draw();
}
和两个实现
public class Square implements TestInterface {
@Override
public void draw() {
System.out.println("Square");
}
}
和
public class Circle implements TestInterface {
@Override
public void draw() {
System.out.println("Circle");
}
}
现在我可以轻松做到
TestInterface a = new Square();
a.draw();
我正确地得到 Square
。接下来,我想试试反射。
Class<?> clazz = null;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Constructor<?> constructor = null;
try {
constructor = clazz.getConstructor();
} catch (NoSuchMethodException | SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Object instance = null;
try {
instance = constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Method method = null;
try {
method = instance.getClass().getMethod(methodName);
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
method.invoke(instance);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
和 className
作为 some.package.Square
和 methodName
作为 draw
我再次得到 Square
。哪个是正确的。
问题是我的应用程序可以访问 interface
但不能访问实际的实现。因此我知道要调用哪些方法,但我还必须指定已实现的 classes 并且我不知道它们可能驻留在哪个包中。如果我只知道 class 但不是包?
有没有办法让我仍然可以使用
的初始化形式TestInterface a = new <some_parameter>();
a.draw();
有没有办法概括它?还是我上面展示的使用反射的方法是实现类似目标的唯一方法?最后,如果我使用抽象 class 而不是接口,会有什么不同吗?
你必须知道 class 的全名。仅 class 的名称不足以将其加载到内存中并通过反射使用它。但是,您可以使用 reflections 库确定接口的实现。
也许这个讨论帖可以帮助您:How can I get a list of all the implementations of an interface programmatically in Java?
您需要通过:
@param className the fully qualified name of the desired class.
例如当您有三个 class 具有相同的名称但在不同的包中时
--package1
----Test
--package2
----Test
Main
Test
在 Main 中你有:
public static void main(String[] args) throws UnsupportedEncodingException {
Class<?> clazz = null;
try {
clazz = Class.forName("Test");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
它将调用Main级别的那个。要调用其他人,您需要传递完全合格的名称。
clazz = Class.forName("package1.Test");
clazz = Class.forName("package2.Test");
如果我只知道 class 而不知道包的名称怎么办? 所以你需要知道你想要的级别。因为正如您所知,不同的包 classes 可以具有相同的名称。那么,如果您有这个问题,您需要哪个Class。