Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java - Calling a subclass method from dynamically casted superclass

1:

I have a dictionary with a string as key and a class as value, this contains a list of "entities" i have in my game.

private static Map<String, Class> entitiesList = new HashMap<String, Class>();
public static void initEntitiesList()
{
    entitiesList.put("npc_something", NpcSomething.class);
    entitiesList.put("npc_thing", NpcThing.class);
    entitiesList.put("npc_stuff", NpcStuff.class);
    ...
}

2:

Here's an example hierarchy.

Entity (abstract)
^
Mobile (abstract)
^
BaseCreature (abstract)
^
NpcSomething

-Entity contains a method called "public void Input(String args)", which can be redefined in the other entities.
-When i call Input("x") on NpcSomething it should do a super(arg) chain from it's own class to Entity's class.
-All those classes above have a constructor allowing string as argument.

3:

I have an independent static method used to create new instances of my entities, which goes as such:

public static boolean createEntity(String entName, String args)
{
    Class<?> entClass = null;
    if ((entClass = entitiesList.get(entName)) != null)
    {
        Entity ent;
        try
        {
            ent = (Entity)entClass.getDeclaredConstructor(String.class).newInstance("");

            //this here failed.
            //Method method = entClass.getMethod("input", new Class[] { ent.getClass() });
            //method.invoke(ent, new Object[] {ent});
            //java.lang.NoSuchMethodException: entities.NpcSomething.input(entities.NpcSomething)

            //this here is really out of place, as i plan on having a hundred of entities and even more...
            //if (entClass.isInstance(NpcSomething.class))

            //i tried stuffs related to:
            //T t = entClass.cast(ent);
            //but i could not understand it at all even with documentation.

            //basically i want to cast ent to entClass to call Input.
            //right now, the line under calls Input on an Entity class, which is what i want to avoid.
            ent.Input("Stuffs");
        }
        catch (InstantiationException ex) { ex.printStackTrace(); }
        catch (IllegalAccessException ex) { ex.printStackTrace(); }
        catch (IllegalArgumentException ex) { ex.printStackTrace(); }
        catch (InvocationTargetException ex) { ex.printStackTrace(); }
        catch (NoSuchMethodException ex) { ex.printStackTrace(); }
        catch (SecurityException ex) { ex.printStackTrace(); }
    }
}

4:

My problem.

EntCreator.createEntity("NpcSomething", "stuffs");
EntCreator.createEntity("NpcThing", "stuffs");
EntCreator.createEntity("NpcStuff", "stuffs");

I want to call Input(); on NpcSomething,
I want to call Input(); on NpcThing,
I want to call Input(); on NpcStuff.
Then those 3 will call their respective superclass code, and so on until they reach Entity.

Those are casted as Entity with "ent = (Entity)entClass.getDec...", because i have Mobile, but also Item, and other classes that inherit Input. Then with that Entity, find the right subclass, and call the Input of that said subclass.

Short line problem: Create "NpcSomething" as an "Entity" then cast the entity to "NpcSomething's class" to call the method "Input(args)".

5:

Answers to quick questions.

-Q: Why doing this?
-A: To create entities with pre-creation arguments, example: creating a ("NpcSomething", "health 20 healthmax 25").

-Q: Why not using instanceof?
-A: I would need more than 200 instanceof in that static class, this would be a bad programming practice.

-Q: Why don't you move your input method in Entity itself?
-A: I have many different entities with different values, ex: NpcThing, the only flying mobile would have flyingSpeed, flyingEnergy... ItemScroll, having text, textColor, textFont... Those are things i can't place in Entity, as it would require instanceof, which is a bad practice for more than ents.

-Q: Do you want to cast NpcSomething to Entity?
-A: Read the whole thing again.

-Q: Could you provide more informations?
-A: I would love to do that too.

-Q: Why don't you declare ent as NpcSomething?
-A: because ent could be ItemStuff, ModelHouse, etc, which are not inheriting from Mobile, or BaseCreature...

6:

I did not find good practical examples of how to do what i want.
I could not find anything especially for this in the documentation.
Any help is welcome.

like image 604
Po0ka Avatar asked Nov 21 '22 21:11

Po0ka


1 Answers

Suppose you got the Entity ent instance from newInstance() method. This is how you invoke input(String) method for that instance:

// See here, the .class argument passed is the type of parameter
// You're using `ent.getClass()` here. It won't work
Method method = ent.getMethod("input", String.class);

// then while invoking this method, you pass the argument:
// Call `invoke()` method of `Method` class
// First arg is the instance on which this method should be called
// Remaining arg is the argument to be passed to the method itself.
result = method.invoke(ent, args);
like image 109
Rohit Jain Avatar answered Nov 24 '22 10:11

Rohit Jain