Java反射:使用接口初始化对象,但使用字符串值作为类名

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java反射:使用接口初始化对象,但使用字符串值作为类名相关的知识,希望对你有一定的参考价值。

可以说我有以下设置

一个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.SquaremethodName作为draw我再次获得Square。哪个是对的。

问题是我的应用程序可以访问interface但不能访问实际的实现。因此,我知道要调用哪些方法,但我必须指定实现的类,我不知道它们可能驻留在哪个包中。如果我只知道类的名称而不是包,该怎么办?

有没有办法我仍然可以使用初始化形式

TestInterface a = new <some_parameter>();
a.draw();

有没有办法概括它?或者是使用我在上面展示的反射的方法,实现这样的事情的唯一方法是什么?最后,如果我使用抽象类而不是接口,它会有什么不同吗?

答案

你需要通过:

@param      className   the fully qualified name of the desired 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级别的那个。要调用其他人,您需要传递完全quallifed名称。

    clazz = Class.forName("package1.Test");
    clazz = Class.forName("package2.Test");

如果我只知道课程的名称但不知道包裹怎么办?所以你需要知道你想要什么级别。因为您知道不同的包类可以具有相同的名称。如果你有这个问题,你需要哪个班级。

另一答案

你必须知道班级的全名。只有类的名称不足以将其加载到内存中并通过反射使用它。但是,您可以使用reflections库确定接口的实现。

也许这个讨论主题可以帮助你:How can I get a list of all the implementations of an interface programmatically in Java?

以上是关于Java反射:使用接口初始化对象,但使用字符串值作为类名的主要内容,如果未能解决你的问题,请参考以下文章

Java面试_君哥讲解笔记_java面向对象_3抽象类和接口有什么区别接口是否可以继承接口private修饰的方法可以通过反射访问,那么private的意义是什么_ java类的初始化/执行顺序

软件工程JAVA反射技术

Java的反射技术

[Java] 反射

java8--类加载机制与反射(java疯狂讲义3复习笔记)

days23--反射