2

I have this Java code snippet:

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

where "command" is a String which is manually entered at runtime. For the sake of the question, let's assume the user enters "Foo".

It checks if there is a class named Foo. The thing I want to do after checking is to call a method from Foo.

Foo.execute();

How do I do this without making a special "if" case for each of my classes? Is there a way to use something like an alias, ($command).execute() where $command would be (in this case) my Foo Class?

Antti Degl
  • 69
  • 8
  • 2
    http://stackoverflow.com/questions/2467544/invoking-a-static-method-using-reflection – Sotirios Delimanolis Nov 20 '15 at 20:26
  • If you want to reference the classes you can input as a single entity I would say use a super class. So, each class that can be input extends or implements InputClazz.class or something – Mason T. Nov 20 '15 at 20:26
  • Hi, Please have a look at the command Pattern. Just store your Commands in a HashMap. : http://www.javaworld.com/article/2077569/core-java/java-tip-68--learn-how-to-implement-the-command-pattern-in-java.html – Marcinek Nov 20 '15 at 20:26
  • Marcinek has the best idea, I'd go that route if possible. Can you update your question to reflect how much leeway you have implementing this? – markspace Nov 20 '15 at 20:28
  • Possible duplicate of [Create new class from a Variable in Java](http://stackoverflow.com/questions/1268817/create-new-class-from-a-variable-in-java) – krilovich Nov 20 '15 at 20:29
  • My advice? You want JavaScript not Java. Run the JavaScript engine built into the JDK. – duffymo Nov 20 '15 at 20:31

4 Answers4

2

My first instinct would be for any class you want to be able to execute from name would be to make each one implement a common interface.

Example:

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
  }
}

How to invoke:

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

You can then input either Foo or Bar and the code will run the concrete execute methods of the class.

Mason T.
  • 1,567
  • 1
  • 14
  • 33
0

You must use the reflection and the invoke method like this:

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

See this tutorial for details: https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html

JFPicard
  • 5,029
  • 3
  • 19
  • 43
0

This prints "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");
}

The only thing not as nice is that you'll have to use the fully qualified class name. So instead of Foo it's likely something ugly like com.mycompany.something.Foo. Or you really have to make sure those classes are in no package.

zapl
  • 63,179
  • 10
  • 123
  • 154
0

I think Nappa has a good, practical answer. If you want to be a little fancier, you can check your class for membership in a hierarchy with isAssignableFrom() on the Class method.

The code below uses a built-in hierarchy (StringBuilder implements the CharSequence interface). When it finds a class of type CharSequence, it casts the class and then calls length() on it.

You can maintain control of your class types without throwing exceptions, which might be a little cleaner in some circumstances.

Note that this code still throws ClassNotFoundExcpetion if you spell then name of a class incorrectly. You must still catch that exception.

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

Sample code output:

run:
0
nope
BUILD SUCCESSFUL (total time: 0 seconds)
markspace
  • 10,621
  • 3
  • 25
  • 39