aimlesslegs
aimlesslegs

Reputation: 41

Java get superclass method to use subclass instance method when called by subclass

I am attempting to get a superclass method to run on subclass methods/fields when called by the subclass. For instance

public class CoffeeMachine() {
    protected int cost = 3;

    protected int getCost() {
        return cost;
    }
}

public class FancyCoffeeMachine() extends CoffeeMachine{
    protected int cost = 6;
}

main{
    FancyCoffeeMachine expensive = new FancyCoffeeMachine();
    System.out.println(expensive.getCost());
}

I would like this to print 6, but it prints 3 instead. I want to make this as DRY as possible, so I am trying to avoid making a second getCost() method. Is there any way to do this? How can I get a superclass method to use subclass variables, when called by the subclass? The same thing happens with methods: if I have

public class makeCoffee() {
    System.out.println("Coffee cost " + this.getCost());
}

the output will be "Coffee cost 3" even when I call makeCoffee on a FancyCoffeeMachine. Why is this? How can I fix it? Or is there a better way to implement this object structure that completely circumvents this mistake?

Upvotes: 1

Views: 357

Answers (4)

Kenster
Kenster

Reputation: 25458

You wouldn't normally redefine a protected field like cost in a subclass. Instead, you would give the subclass a way to set the cost while constructing the object. Look at this:

public class Scratch {
    public static class CoffeeMachine {
        protected int cost;

        public CoffeeMachine() {
            this(3);
        }

        protected CoffeeMachine(int aCost) {
            cost = aCost;
        }

        public int getCost() {
            return cost;
        }
    }

    public static class FancyCoffeeMachine extends CoffeeMachine{
        public FancyCoffeeMachine() {
            super(6);
        }
    }

    public static void main(String[] args) {
        System.out.printf("plain: %d\n", new CoffeeMachine().getCost());
        System.out.printf("fancy: %d\n", new FancyCoffeeMachine().getCost());
    }
}

(Don't worry about the fact the two CoffeeMachine classes are declared static. That's just so they can all be defined in one file.)

The base class CoffeeMachine has two constructors:

  1. A protected constructor which accepts a cost as an argument.
  2. A public constructor which sets the cost to 3.

The subclass FancyCoffeeMachine calls the protected superclass constructor with a cost of 6. So the cost variable is set to 6 and getCost() will return that value when you run it:

plain: 3
fancy: 6

Upvotes: 0

SamHoque
SamHoque

Reputation: 3154

I am pretty sure you have to override getCost() on FancyCoffeeMachine too.

public class FancyCoffeeMachine() extends CoffeeMachine{
    protected int cost = 6;

    protected int getCost() {
        return cost;
    }
}

But If I wanted to implement this what I would do is make CoffeeMachine abstract like this

abstract class CoffeeMachine {
    private int cost;

    CoffeeMachine(int cost) {
        this.cost = cost;
    }

    int getCost() {
        return cost;
    }
}

and then extend it on my superclass like this

class FancyCoffeeMachine extends CoffeeMachine {
    FancyCoffeeMachine(int cost) {
        super(cost);
    }
}

and call it as such

FancyCoffeeMachine fancyCoffeeMachine =  new FancyCoffeeMachine(6);
System.out.println(fancyCoffeeMachine.getCost());

Upvotes: 0

httpdigest
httpdigest

Reputation: 5806

Linking fields does not use dynamic dispatch as virtual method calls do. Your field FancyCoffeeMachine.cost simply hides the field CoffeeMachine.cost.

To achieve what you want (i.e. FancyCoffeeMachine having a higher cost) you can simply set a new value to the CoffeeMachine.cost field within an initializer block or constructor in FancyCoffeeMachine.

public class CoffeeMachine {
    protected int cost = 3;

    protected int getCost() {
        return cost;
    }
}
public class FancyCoffeeMachine extends CoffeeMachine{
    {cost = 6;} // <- sets CoffeeMachine.cost
}

Upvotes: 2

Vlad Hanzha
Vlad Hanzha

Reputation: 464

You're calling method getCost from superclass(CoffeeMachine) because you don't have it in your subclass(FancyCoffeeMachine). And your superclass doesn't know anything about subclass and its field cost. You should also override method getCost to get it working like you described.

Upvotes: 0

Related Questions