Typhaon Typhaon - 2 months ago 9
Java Question

Can i change the class of an variable in an abstract class

In my current project I have a couple of classes that inherit variables from an abstract class. One of the similarities is that they all need to cal for a new specific controller class, based on which extension of the abstract class they are. These classes also have loads of similarities and one of them is that they save which object has constructed them.

Now I am trying to make an abstract class for these controller classes, and I have made an variable of the abstract class that would create them. Where the problem lies now is that I need my the implementations of this controller class to change the abstract creator class to the implementation of the controller class

That sounds really confusing. I will write down an example:

public abstract class ObjectController {
protected GameObject gameObject;
protected Game gameVersion;

public ObjectController(GameObject object, Game gameVersion){
this.gameObject = object;
this.gameVersion = gameVersion;
}
public abstract void nextAction();
}


So that's my abstract Controller class, I will write down an example of a controller class that extends this. This class needs to save an object that extends the abstract GameObject class. Although, since I'm pretty sure that after constructing this class the 'gameObject' variable is filled with an specific extension of GameObject, I want to do things with this variable that only that extension can do.

public class PlayerController extends ObjectController {
int speed = 0;
public PlayerController(Player player, Game gameVersion{
super(player, gameVersion)
}
public void updateSpeed(){
speed = player.getSpeed() // example of a method only the Player class has
}
}


How do I do this without constantly casting the player variable to the Player class?

Answer

If you're running into this problem with all your Controllers, I recommend using a generic:

abstract class ObjectController<T extends GameObject> {
    protected T gameObject;
    protected Game gameVersion;

    public ObjectController(T object, Game gameVersion){
        this.gameObject = object;
        this.gameVersion = gameVersion;
    }
    public abstract void nextAction();
}

class PlayerController extends ObjectController<Player> {

    public PlayerController(Player object, Game gameVersion) {
        super(object, gameVersion);
    }

    @Override
    public void nextAction() {
        //Work with your Player here
    }

}

When you make a controller that extends ObjectController, you're forcing the T gameObject of the superclass to conform to some type that is instanceof GameObject. That way, any mention of T in the generic superclass becomes the type you want to work with.

Edit: If you want to reference a GameObject's ObjectController:

public class GameObject {
    private ObjectController<? extends GameObject> controller;

    //Getter/setter for controller
}

You can even instantiate the controller in the GameObject's constructor, if you like.

The wildcard ? more or less tells the compiler that this generic will "be of some class instanceof GameObject" at runtime. The wildcard can be a little hard to work if you're being conscious of the class type when coding, but since you know each controller's generic type is that of the GameObject's class, you should be able to simply access it via object.getController().