如果 class 存在,调用构造函数

If class exists, call constructor

我有这个 Java 代码片段:

try {
    Class.forName(command);
} catch (ClassNotFoundException ex) {    
}

其中 "command" 是一个在运行时手动输入的字符串。为了这个问题,我们假设用户输入 "Foo".

它检查是否有一个名为 Foo 的 class。检查后我想做的事情是从 Foo 调用一个方法。

Foo.execute();

如何在不为每个 classes 制作特殊 "if" 案例的情况下执行此操作?有没有办法使用别名之类的东西,$command.execute() 其中 $command 将是(在这种情况下)my Foo Class?

您必须像这样使用反射和调用方法:

Object o = m.invoke(t, new Locale(args[1], args[2], args[3]));

详见本教程:https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html

我的第一直觉是,对于任何 class 你希望能够从 name 执行的是让每个实现一个通用接口。

示例:

public Interface InputClazz {
    public void execute();
}

public class Foo implements InputClazz {
  public void execute() {
    //do Stuff
  }
}

public class Bar implements InputClazz {
  public void execute() {
    //do Stuff
  }
}

如何调用:

try {
    Class clazz = Class.forName(command);
    InputClazz input = (InputClazz) clazz.newInstance();
    input.execute();
} catch (ClassNotFoundException ex) {    
}

然后您可以输入 Foo 或 Bar,代码将 运行 class 的具体执行方法。

这会打印 "Hello World"

private static void call(String className, String methodName) {
    try {
        Class<?> clazz = Class.forName(className);
        Object instance = clazz.newInstance();
        Method method = clazz.getMethod(methodName);
        method.invoke(instance);
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}

static class Foo {
    public void foo() {
        System.out.println("Hello World");
    }
}

public static void main(String[] args) {
    call(Foo.class.getName(), "foo");
}

唯一不好的是您必须使用完全限定的 class 名称。因此,它可能不是 Foo,而是像 com.mycompany.something.Foo 这样丑陋的东西。或者你真的必须确保那些 classes 不在包中。

我认为 Nappa 有一个很好、实用的答案。如果您想更高级一点,可以使用 Class 方法使用 isAssignableFrom() 检查您的 class 是否属于层次结构。

下面的代码使用内置层次结构(StringBuilder 实现了 CharSequence 接口)。当它找到类型为 CharSequence 的 class 时,它会转换 class,然后对其调用 length()

您可以在不抛出异常的情况下保持对 class 类型的控制,这在某些情况下可能更简洁。

请注意,如果您拼错 class 的名字,此代码仍会抛出 ClassNotFoundExcpetion。您仍然必须捕获该异常。

public class ReflectionSubclassing
{

   public static void main(String[] args) 
           throws ClassNotFoundException, InstantiationException, 
           IllegalAccessException 
   {
      getDoubleValue( "java.lang.StringBuilder" );
      getDoubleValue( "javax.swing.JButton" );
   }

   private static void getDoubleValue( String className ) 
           throws ClassNotFoundException, InstantiationException, 
           IllegalAccessException
   {
      Class<?> tempClass = Class.forName( className );
      if( java.lang.CharSequence.class.isAssignableFrom( tempClass ) ) {
         Object charSeq = tempClass.newInstance();
         CharSequence cs = (java.lang.CharSequence)charSeq;
         System.out.println( cs.length() );
      } else
         System.out.println( "nope" );
   }
}

示例代码输出:

run:
0
nope
BUILD SUCCESSFUL (total time: 0 seconds)