Reputation: 41
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
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:
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
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
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
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