Reputation: 4649
public class Flight{
private int flying = 0;
public boolean fly() {
flying = 1;
return isFlying();
}
private isFlying(){
return flying > 0;
}
}
public class CargoFlight extends Flight{
public boolean startFlight(int passengers)
if (passengers <= 0){
return false;
}
return fly(); // Want to be able to do this
}
}
public class Airport{
public static void main(){
CargoFlight f1 = new CargoFlight();
f1.fly(); // Don't want to be able to do this
}
}
f1
has the property fly()
, is there any way to restrict it such that the method fly()
can be called inside the body of the classes extending Flight
(like CargoFlight
here), but cannot be called using the instances of the subclasses (like f1
)? I have added comments to the code to make it clear.
Upvotes: 4
Views: 3639
Reputation: 50061
The nearest access specifier to what you want is protected
. However, protected
members are still always accessible to other classes in the same package, so it won't prevent access from your Airport
class.
If you really need the subclass to block access to the method except to the subclass, then you can override it in the subclass to always throw an exception, then use super
to invoke the original method:
public class Flight {
private int flying = 0;
protected boolean fly() {
flying = 1;
return isFlying();
}
private boolean isFlying() {
return flying > 0;
}
}
public class CargoFlight extends Flight {
@Override
protected boolean fly() {
throw new IllegalAccessError();
}
public boolean startFlight(int passengers) {
if (passengers <= 0) {
throw new IllegalArgumentException();
}
return super.fly();
}
}
The flaw with any solution though, is that it violates the Liskov substitution principle. A CargoFlight
is no longer a proper instance of Flight
because it doesn't have the normal fly
method that other Flight
s have. If you intend fly
only to be called by subclasses and never directly, then it's okay (although you should document that rule in the method Javadoc), but it still leaves you without the nicety of having a polymorphic method to call to tell generic Flight
s to fly
.
A nicer solution, if it can fit with your design, would be to have fly
and startFlight
be the same method (that means same name and same arguments, and the same return type or a subtype), so then the subclass method could simply override the base implementation. The only method outside callers would see is fly
. That means that your passengers
argument either needs to be part of the base method Flight.fly
too, or, remove it from both method implementations and make it into a separate property setPassengers
for those subclasses that need it:
public class CargoFlight extends Flight {
private int passengers = 0;
public void setPassengers(int p) {
passengers = p;
}
@Override
public boolean fly() {
if (passengers <= 0) {
throw new IllegalStateException(); // or whichever
}
return super.fly();
}
}
Upvotes: 6