Consider the following code snippets:
package vehicle;
public abstract class AbstractVehicle {
protected int speedFactor() {
return 5;
}
}
pack
Because protected
is visible to the class itself (like private) and its subclass instances. It is not public.
For example,
package vehicles;
public abstract class AbstractVehicle {
protected int speedFactor() {
return 5;
}
public int getSpeed() {
return 10*speedFactor(); //accessing speedFactor() "privately"
}
}
package vehicles.cars;
public class SedanCar extends AbstractVehicle {
@Override
protected int speedFactor() { //overriding protected method (just to show that you can do that)
return 10;
}
@Override
public int getSpeed() {
return 20*speedFactor(); //this is part of the instance (!!!) therefore it can access speedFactor() protected method too
}
}
package vehicles.main;
public class Main {
public static void main(String[] args) {
AbstractVehicle vehicle = new SedanCar();
int speed = vehicle.getSpeed(); //accessing public method
vehicle.speedFactor(); //cannot access protected method from outside class (in another package)
}
}
The static main()
method is not part of the instance, that is why it cannot access the protected method.
Back in my SCJP for Java 1.5 days, one thing that I used to remember was be wary of superclass reference variables. It isn't quite as surprising to see this now and one thing why this gets confusing is the rule is protected is visible to subclass or same package. What if it's both subclass and different package?
If you create another package, and do
package yetAnotherPackage;
import car.SedanCar;
public class Main {
public static void main(String[] args) {
new SedanCar().speedFactor();
}
}
you'll see that
The method speedFactor() from the type AbstractVehicle is not visible
Looks like the rule just propagates. As long as you have a subclass and try to access the protected method within the package of the subclass (or if no subclass, then the package of the parent), you should be good.
Subclasses in different package can't access protected methods and protected variables from superclass using superclass reference. Only way to access protected data of superclass in subclass is through inheritance
below are two code snippets
package nee;
import parentdata.Parent;
class Child extends Parent{
public void testIt(){
System.out.println(x); // able to access protected x defined in Parent
}
}
package nee;
import parentdata.Parent;
class Child extends Parent {
public void testIt(){
Parent p=new Parent();
System.out.println(p.x) // results in compile time error
}
}
In language specification 6.6.2.1 Access to a protected Member
Let C be the class in which a protected member m is declared. Access is permitted only within the body of a subclass S of C. In addition, if Id denotes an instance field or instance method, then:
If the access is by a qualified name Q.Id, where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S.
If the access is by a field access expression E.Id, where E is a Primary expression, or by a method invocation expression E.Id(. . .), where E is a Primary expression, then the access is permitted if and only if the type of E is S or a subclass of S.
for in depth details visit http://www.jot.fm/issues/issue_2005_10/article3.pdf
Your SedanCar
class is in a different package than the AbstractVehicle
class. protected
methods can only be accessed from the same package or from subclasses.
In case of SedanCar
:
SedanCar sedan = new SedanCar();
sedan.speedFactor();
You are calling a protected
method from the same package: OK. SedanCar
is in package car
and main()
method is in a class which is in package car
(actually the same class).
In case of AbstractVehicle
:
AbstractVehicle vehicle = new SedanCar();
vehicle.speedFactor();
You try to call a protected
method but from another package: NOT OK. The main()
method from which you try to call it is in package car
while AbstractVehicle
is in package vehicle
.
Basically understand this:
You have a variable of type AbstractVehicle
which is declared in another package (vehicle
). It may or may not hold a dynamic type of SedanCar
. In your case it does, but it could also hold an instance of any other subclass defined in another package, e.g. in sportcar
. And since you are in package car
(the main()
method), you are not allowed to invoke vehicle.speedFactor()
(which is the protected AbstractVehicle.speedFactor()
).
The protected modifier specifies that the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package.
This is the reason why you can't directly call the method inside the main method on the vehicle object.
See: https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html