9

Consider the following code snippets:

package vehicle;

public abstract class AbstractVehicle {
    protected int speedFactor() {
        return 5;
    }
}

package car;

import vehicle.AbstractVehicle;

public class SedanCar extends AbstractVehicle {
    public static void main(String[] args) {
        SedanCar sedan = new SedanCar();
        sedan
                .speedFactor();
        AbstractVehicle vehicle = new SedanCar();
        // vehicle //WON'T compile
        // .speedFactor();
    }
}

SedanCar is a subclass of AbstractVehicle which contains a protected method speedFactor. I am able to call the method speedFactor if it is referenced by the same class. When the super class is used for reference the method speedFactor is not accessible.

What is reason for hiding the method?

icza
  • 389,944
  • 63
  • 907
  • 827
Hariharan
  • 881
  • 1
  • 13
  • 25
  • 2
    Because `protected` is visible to the class itself (like `private`) and its subclasses. It is **not public**. – EpicPandaForce Jun 01 '15 at 07:39
  • 1
    `protected` instance methods are visible to the class itself, and to _instances_ of subclasses, but not to static methods in subclasses. – khelwood Jun 01 '15 at 07:41
  • But SedanCar is a subclass of AbstractVehicle. – Hariharan Jun 01 '15 at 07:41
  • vehicle.speedFactor will be not accessible – Hariharan Jun 01 '15 at 07:42
  • If you create a method in your `SedanCar` class, in that method you can call `speedFactor`. But not using object. – Naman Gala Jun 01 '15 at 07:43
  • @khelwood: I just want to clarify -- even if he had instantiated `AbstractVehicle vehicle = new SedanCar();` inside an instance method (non-static) of `SedanCar`, the code would still not compile. The `speedFactor()` method can only be accessed through a reference to the subclass itself, if from an outside package. – John Thompson Aug 11 '16 at 15:06

5 Answers5

7

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()).

icza
  • 389,944
  • 63
  • 907
  • 827
  • 1
    I'm kind of surprised that it can't be called from a class that extends AbstractVehicle. Yes, it's inside a static method, but the method is enclosed by a class that extends AbstractVehicle. It kinda makes sense because static methods don't participate in inheritance, but it still surprised me. – markspace Jun 01 '15 at 07:47
  • @markspace Because the method you try to call is not `SedanCar.speedFactor()` but `AbstractVehicle.speedFactor()`. Yes, virtually it will be `SedanCar.speedFactor()` but you are referring to `AbstractVehicle.speedFactor()` which is a `protected` method in another package. – icza Jun 01 '15 at 07:53
  • Back in my SCJP for 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. – Praba Jun 01 '15 at 07:56
  • I have tried creating another class in car package, if the protected method is overriden in SedanCar I am able to access it. Otherwise it is restricted. why is it so? – Hariharan Jun 01 '15 at 08:47
  • @harinewton Most likely because you are referring to the overridden `speedFactor()` method declared in the same package (`car`) and not to the original one declared in another package. Show your new code if this is not satisfactory and you want more explanation. – icza Jun 01 '15 at 08:49
  • The explanation you have given is satisfactory, but I am asking if the protected method has been overriden it is also getting package private access. Why it is so? – Hariharan Jun 01 '15 at 08:53
  • Consider I have overriden method public class SedanCar extends AbstractVehicle { @Override protected int speedFactor() { return super .speedFactor(); } – Hariharan Jun 01 '15 at 08:57
  • Now from the classes I have created in the same package I can access speedFactor(). But why it is allowed – Hariharan Jun 01 '15 at 08:58
  • @harinewton When you override a method, you can use the same access modifier as the method was declared in the super class or you can widen it. E.g. if there is a `protected` method in the superclass, you may choose to override it and keep it `protected` or make it `public`. And you can access it in the subclass because you are referring to `SedanCar.speedFactor()` **not** `AbstractVehicle.speedFactor()`. And `protected` means you can call it from subclasses and from the same package. Overriding a method (being `protected`) and calling it from the same class - that is the same package. – icza Jun 01 '15 at 09:00
4

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.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • 1
    w.r.t your last line - "The static main() method is not part of the instance, that is why it cannot access the protected method." - Even i am not able to access it from a non static method. – Ouney Jun 01 '15 at 08:26
  • @Ouney well if it is a non-static method within `SedanCar`, then you should be able to access it. – EpicPandaForce Jun 01 '15 at 08:40
  • That is what i expected as well but it is not so :( – Ouney Jun 01 '15 at 09:02
  • @Ouney well, the example I provided worked (although I did need to move the Main to another package to get the error provided in the question - because `protected` is also `package private`.) – EpicPandaForce Jun 01 '15 at 09:10
  • So, you are saying that if SedanCar is in different package than AbstractVehicle, then you can safely invoke this (Assume this code to be in a non static method.) - AbstractVehicle vehicle = new SedanCar();vehicle.speedFactor() ?? – Ouney Jun 01 '15 at 12:27
2

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

Jan Koester
  • 1,178
  • 12
  • 26
1

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

Mausam Sinha
  • 153
  • 2
  • 16
0

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.

Praba
  • 1,373
  • 10
  • 30