简体   繁体   中英

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.

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

Because the method call has a higher priority than the cast. You should force the cast before the method call by surrounding it with brackets

ent = ((Entity)entClass).getDeclaredConstructor(String.class).newInstance("");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM