Java call class by string

how to call class using strings

Use reflection, although it’s not obvious that that’s what you’re looking for. And you might need to review Java syntax before you proceed.

dont edit, if dont get the qus..please i wanted to dynamically give the name if i already know it is class «A» why i will be using this..approach..huh

2 Answers 2

Your code doesn’t make a lot of sense, because des is not a field of the String array className . However, it looks like you’re trying to access a field declared in class A based on just having the name of the class as a String value. Since des is an instance field, you need an instance of A to work with. You can do something like this:

A a = (A) (Class.forName("A").newInstance()); System.out.println(a.des[0]); 

You’ll have to add code to deal with the potential exceptions that this can throw. Also note that the argument to Class.forName needs to be the full name of the class, so if A is part of a package (say com.example ), then it would have to be Class.forName(«com.example.A») .

Here’s how to combine Sotirios Delimanolis’s and my code into a complete working example:

class Example < static class A < String[] des = < "Hi from class A" >; > static class B < String[] des = < "Hi from Class B" >; > public static void main(String[] args) < String[] classNames = < "Example$A", "Example$B" >; // inner class names for (String name : classNames) < try < System.out.println(getDes0(name)); >catch (Exception e) < System.err.println("Could not get des[0] for class " + name); e.printStackTrace(); >> > private static String getDes0(String className) throws Exception // better to be explicit, but distracts from the answer < Classcls = Class.forName(className); Field field = cls.getDeclaredField("des"); Object obj = cls.newInstance(); String[] des = (String[]) field.get(obj); return des[0]; > > 

Источник

Читайте также:  Html border color div style

How to call a method by name (String) in Java?

Every instance of class A has an instance of class B . A should call different methods in B depending on its member variable method_num . This is an implementation that does what I want:

public class A < private B myB = new B(); public int method_num = 1; public callBMethod() < if ( method_num == 1 ) myB.method1(); else myB.method2(); >> public class B < public method1() < >public method2() < >> 

But instead of doing myA.method_num = 1 , I want to be able to somehow pass B’s method1 or method2 directly. How can I do that?

@Andreas: there’s no such a thing, unfortunately. But in any case, you wouldn’t be passing the name, then.

5 Answers 5

If you don’t want to use reflection (and this is an excellent goal) then there are some neat features of enum s that allow you to set up an enum as a proxy.

public class A < private B myB = new B(); public int method_num = 1; public void callBMethod() < // Could do it by name. BMethods.valueOf("method1").call(myB); // Or by number. BMethods.values()[method_num].call(myB); >> enum BMethods < method1 < @Override public void call(B b) < b.method1(); >>, method2 < @Override public void call(B b) < b.method2(); >>; public abstract void call (B b); > public class B < public void method1() < >public void method2() < >> 

@Woot4Moo — er . for each method in class B you need an enum that proxies it. I accept that this becomes cumbersome as the number of methods in B increases but it avoids reflection which, to me, is a laudable gain.

Sure agree. I would treat it as just another «interface» between two modules. Just wanted to mention the scaling piece for future readers.

In the same vein — using this method it is still possible to trace all users of every method of B and be absolutely sure you have them all. Once you use reflection — anywhere in your code — this is no longer possible.

I think you can use reflection like this:

java.lang.reflect.Method method; try < method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..); >catch (SecurityException e) < // . >catch (NoSuchMethodException e) < // . >try < method.invoke(obj, arg1, arg2. ); >catch (IllegalArgumentException e) < //do proper handling >catch (IllegalAccessException e) catch (InvocationTargetException e) 

You cannot. Java doesn't treat functions as first class objects, because it doesn't have functional features like Python or C#.

You can create a Command interface and pass that object reference:

@duffymo & arshajii -- Every "improvement" to Java since about 1.2 has been done in the worst possible way, further corrupting what was originally a very "clean" design. It's not the added function, it's the way it's apt to be designed and implemented.

Maybe with Runnable objects ? You can pass from B a runnable, and call .run() directly from A

@Woot4Moo: While I agree this is a short (too short?) answer, I thought that using a runnable object is both appropriate and not already in existing answers.

ah yes agree it wasn't in other answers, but it didn't provide a code based solution like the others 🙂

Java reflection API provides you a way, where a Method type of object could be passed along with the target object and then the method could be invoked on the target object.

Method m; // The method to be invoked Object target; // The object to invoke it on Object[] args; // The arguments to pass to the method // An empty array; used for methods with no arguments at all. static final Object[] nullargs = new Object[] <>; /** This constructor creates a Command object for a no-arg method */ public Command(Object target, Method m) < this(target, m, nullargs); >/** * This constructor creates a Command object for a method that takes the * specified array of arguments. Note that the parse() method provides * another way to create a Command object */ public Command(Object target, Method m, Object[] args) < this.target = target; this.m = m; this.args = args; >/** * Invoke the Command by calling the method on its target, and passing the * arguments. See also actionPerformed() which does not throw the checked * exceptions that this method does. */ public void invoke() throws IllegalAccessException, InvocationTargetException < m.invoke(target, args); // Use reflection to invoke the method >

Источник

Loading a Class from a String

I want to instantiate a class by the value of a String. I found several tutorials that show several methods for doing this. The class MUST inherit from a certain interface, ImplementMe which has a special method called runMe() . So here's what I tried:

ImplmentMe a = (ImplementMe) ImplementMe.class .getClassLoader() .loadClass("my.package.IImplementedYou") .newInstance(); a.runMe(); 

It works, but it's so ugly. I at least expected not needing a cast. Please tell me there is a better way.

That's so odd. I thought by using ImplementMe.class.getClassLoader() , it would take the hint that the class must inherit from ImplementMe ..oh well.

Class has a asSubclass method. So . loadClass(. ).asSubclass(ImplementMe.class).newInstance() will return an ImplementMe instance (if it succeeds).

9 Answers 9

No, there is no better way (by design). You are not supposed to do this, Java is designed as a type-safe language. However, I can understand that you sometimes need to do things like this, and for that purposes you can create a library function like this:

public T instantiate(final String className, final Class type) < try< return type.cast(Class.forName(className).newInstance()); >catch(InstantiationException | IllegalAccessException | ClassNotFoundException e) < throw new IllegalStateException(e); >> 

Now your client code can at least call this method without casting:

MyInterface thingy = instantiate("com.foo.bar.MyInterfaceImpl", MyInterface.class); 

You need no unchecked cast. Just use return type.cast(Class.forName(className).newInstance()); . The advantage is that it throws immediately (it's more fail-fast).

ImplementMe noCastNeeded = this.getClassLoader() .loadClass("my.package.IImplementedYou") .asSubclass(ImplementMe.class).newInstance(); 

There are some Exceptions to catch but that's ok I think. 🙂

In all essence that is what will happen regardless of whether you're using a third party toolkit for it or not. Casting the object will inherently be mandatory unless expecting an Object . You can however make a routine which does that for you:

public T instantiateObject(String name, Class cls) throws Exception
AClass cls = instantiateObject("com.class.AClass", AClass.class); 

But if you come this far, the String name is actually redundant (given AClass is a concrete class). You might as well:

public T instantiateObject(Class cls) throws Exception
AClass cls = instantiateObject(AClass.class); 

(T) Class.forName(cls.getCanonicalName()).newInstance(); why so complicated? how about cls.newInstance(); ? But in my interpretation, the interface class is loaded, but not the implementation class

True, cls.newInstance() would be shorter. Also using the second approach it has to be a concrete class.

You can shorten it a bit like

ImplementMe a = (ImplementMe) Class .forName("my.package.IImplementedYou") .newInstance(); 

but you can't get rid of the cast. There may be a way to avoid the cast, but only if you can avoid the subproblem of loading class by name.

The alternative is to use forName , but it does not get much better than what you currently have:

ImplementMe a = (ImplementMe) Class.forName("my.package.IImplementedYou").newInstance(); a.runMe(); 

Indeed, forName will use getClassLoader().loadClass() behind the scenes to load the class, as you can see in the source code of Class.java .

You will need a cast, because the compiler cannot tell from the code that the object is of type ImplementMe. It thus requires the programmer to issue a cast, which will throw a ClassCastException if the object is not an ImplementMe instance.

What you have may work, but you don't have to load the class using the same classloader that loaded ImplementMe. This should work equally well:

Object newInstance = this.getClass().getClassLoader().loadClass("my.package.IImplementedYou").newInstance(); 

The important thing is that the classloader knows both the class file with the implementation of "my.package.IImplementedYou" and the class with the implementation of "ImplementMe".

You may explicitly check that IImplementedYou really implements ImplementMe like this:

if(newInstance instanceof my.package.IImplementedYou)

You may also check that IImlementedYou really is implementing the interface before creating the instance:

Class c = this.getClass().getClassLoader().loadClass("my.package.IImplementedYou"); if(ImplementMe.class.isAssignableFrom(c))

Источник

Java-How do I call a class with a string?

I am a beginner programmer and this is my first question on this forum. I am writing a simple text adventure game using BlueJ as a compiler, and I am on a Mac. The problem I ran into is that I would like to make my code more self automated, but I cannot call a class with a string. The reason I want call the class and not have it all in an if function is so that I may incorporate more methods. Here is how it will run currently:

public class textadventure < public method(String room)< if(room==street)> > public class street < public enterRoom()< //do stuff and call other methods >> 

The if statement tests for every class/room I create. What I would like the code to do is automatically make the string room into a class name that can be called. So it may act like so:

I have already looked into using Class.forName, but all the examples were too general for me to understand how to use the function. Any help would be greatly appreciated, and if there is any other necessary information (such as more example code) I am happy to provide it. -Sebastien Here is the full code:

import java.awt.*; import javax.swing.*; public class Player extends JApplet < public String textOnScreen; public void start()< room("street1"); >public void room(String room) < if(room=="street1")< textOnScreen=street1.enterRoom(); repaint(); >if(room=="street2") < textOnScreen=street2.enterRoom(); repaint(); >> public void paint(Graphics g) < g.drawString(textOnScreen,5,15); >> public abstract class street1 < private static String textToScreen; public static String enterRoom()< textToScreen = "You are on a street running from North to South."; return textToScreen; >> public abstract class street2 < private static String textToScreen; public static String enterRoom()< textToScreen = "You are on another street."; return textToScreen; >> 

There are much better ways to do this. This approach you're describing is a huge code smell. (Egads, "stringly typed" code.)

If Java, Public should be lowercase, string should be titlecase. textadventure should, by convention if not by grammar, also be titlecase.

And it doesn't make a lot of sense to name a method "method". If you take a break from programming for a while and come back to rework your code, you will find names like "method" quite confusing and uninforming.

Indentation is your friend, the same is true for coding guidelines, if you want other people to read your code.

4 Answers 4

Seeing as you are rather new to programming, I would recommend starting with some programs that are simpler than a full-fledged adventure game. You still haven't fully grasped some of the fundamentals of the Java syntax. Take, for example, the HelloWorld program:

Notice that public is lowercased. Public with a capital P is not the same as public .

Also notice that the String class has a capital S .* Again, capitalization matters, so string is not the same as String .

In addition, note that I didn't have to use String string = new String("string") . You can use String string = "string" . This syntax runs faster and is easier to read.

When testing for string equality, you need to use String.equals instead of == . This is because a == b checks for object equality (i.e. a and b occupy the same spot in memory) and stringOne.equals(stringTwo) checks to see if stringOne has the same characters in the same order as stringTwo regardless of where they are in memory.

Now, as for your question, I would recommend using either an Enum or a Map to keep track of which object to use.

public class Tester < public enum Location < ROOM_A("Room A", "You are going into Room A"), ROOM_B("Room B", "You are going into Room B"), OUTSIDE("Outside", "You are going outside"); private final String name; private final String actionText; private Location(String name, String actionText) < this.name = name; this.actionText = actionText; >public String getActionText() < return this.actionText; >public String getName() < return this.name; >public static Location findByName(String name) < name = name.toUpperCase().replaceAll("\\s+", "_"); try < return Enum.valueOf(Location.class, name); >catch (IllegalArgumentException e) < return null; >> > private Location currentLocation; public void changeLocation(String locationName) < Location location = Location.findByName(locationName); if (location == null) < System.out.println("Unknown room: " + locationName); >else if (currentLocation != null && currentLocation.equals(location)) < System.out.println("Already in room " + location.getName()); >else < System.out.println(location.getActionText()); currentLocation = location; >> public static void main(String[] args) < Tester tester = new Tester(); tester.changeLocation("room a"); tester.changeLocation("room b"); tester.changeLocation("room c"); tester.changeLocation("room b"); tester.changeLocation("outside"); >> 

*This is the standard way of formating Java code. Class names are PascalCased while variable names are camelCased .

Источник

Оцените статью