Search code examples
javaobjectclasscastexception

Java: ClassCastException; casting Player class to class that extend Player


I am having trouble understanding how to fix this issue of creating a bot that extends the Player class in my online multiplayer game.

If I try to make classes that extend Player (NPC_Type1, NPC_Type2, etc..), I want to be able register with the extended class not the Player since each class will do something different.

Just casting it to the proper type gives me an error:

Cast Example:

NPC_Type1 p = (NPC_Type1)registerPlayer(null)

java.lang.ClassCastException: class com.testgame.server.model.player.Player cannot be cast to class com.testgame.server.model.player.NPC_Type1 (com.testgame.server.model.player.Player and com.testgame.server.model.player.NPC_Type1 are in unnamed module of loader 'app')

PlayerManager Code:


 private List<Player> players = new ArrayList<>(); // keep track of players in game (maybe bots to?)

 public Player registerPlayer(Channel c) { //netty channel
        Player player = new Player(context, c);
        if ((!player.isBot())) // bots are exempt
        {
            //do stuff
            return player;
        }
        players.add(player); // add player to list
 }

 public Player createBot(
        String name,
        int ID,
        int[] startPosition,
        float startDamage
    ) {
        Player p = registerPlayer(null); //cast error here
        p.register(
                name,
                ID,
                startPosition,
                startDamage,
        );
        return p;
    }
// adding bots to a list
 public List<? extends Player> listBots() {
     List<? extends Player> bot = new ArrayList<>();
     for (Player p : bots) {
         if (p.isRegistered() && p.isBot()) {
             bot.add(p); //compile error
         }
     }

     return bot;
 }

Can someone explain what I am doing wrong and how to fix with maybe a small example?


Solution

  • An object can be cast to it's own class or a class that it extends (any class in the hierarchy down to Object) as well as any interface it implements. Player is your base class here which are extended by your NPC_TypeX classes. Therefore, an NPC_TypeX object can be cast to Player but not the other around.

    This works:

    Player p = new NPC_Type1();
    

    This does not:

    NPC_Type1 p = new Player(); // Syntax error
    

    Also

    Player p = new NPC_Type1();
    NPC_Type1 n = (NPC_Type1) p; // This is fine since p is of type NPC_Type1
    
    Player p2 = new Player();
    NPC_Type1 n2 = (NPC_Type1) p2; // ClassCastException
    

    In your registerPlayer method you are instantiating Player objects, not NPC_TypeX objects.

    Since you may want to be able to register any Player type you could pass the Player object (or objects of an extending class) into the method if you change the method:

     public Player registerPlayer(Channel c, Player player) { //netty channel
            if ((!player.isBot())) // bots are exempt
            {
                //do stuff
                return player;
            }
            players.add(player); // add player to list
     }
    

    Using thet method:

    NPC_Type1 npc = new NPC_Type1();
    registerPlayer(null, npc);