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?
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()).
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.
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
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
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.
Related
Normally it is said that when we are using protected for a field in a class then its subclass cannot access it using a reference of the Base Class given that the subclass is in a different package . That is true . But I found that it behaves differently when a static keyword is added with the field . It becomes accessible . How is it possible . Is any one having the answer .
package com.car;
public class Car {
static protected int carNo=10;
}
package com.bmw;
import com.car.*;
public class BMW extends Car {
public static void main(String[] args) {
//Its accessible here
System.out.println(new Car().carNo);
}
}
6.6.2.1. Access to a protected Member
Let C be the class in which a protected member 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.
Source : https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.2.1
see
public class BMW extends Car {
public static void main(String[] args) {
System.out.println(new BMW().carNo);
}
}
is valid because new BMW() is a subclass of Car, even being in a different package.
public class BMW extends Car {
public static void main(String[] args) {
System.out.println(new Car().carNo);
}
}
is not valid because new Car() is not a subclass of Car, and it's being called in a different package. (see Java: Is a class a subclass of itself? for a discussion if a class is subclass of itself)
Now, if carNo is static, this is legal
System.out.println(new Car().carNo);
However, the right syntax here would be
System.out.println(Car.carNo);
because carNo is not an instance field, since it's static. In fact, even this will work from inside BMW
System.out.println(carNo);
because
Only members of a class that are declared protected or public are inherited by subclasses declared in a package other than the one in
which the class is declared
as stated at https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.2
The main method is in BMW, that is a subclass of Car. Thus, it has access to the protected variable.
The reason it was not visible before was because static methods, like main, cannot access non-static variables. Once both criterias are fullfilled, the main method can access it.
class Car {
protected int a = 9;
}
class BMW extends Car{
public static void main(String[] args) {
int b = a; // cannot make a static reference to a non static field warning error shown by eclipse
}
}
Two ways to remove it:
either make a static
class Car {
protected static int a = 9;
}
class BMW extends Car{
public static void main(String[] args) {
int b = a; // cannot make a static reference to a non static field
}
}
or call it outside main in a non static method, main being static cannot call to class variables
class Car {
protected static int a = 9;
}
class BMW extends Car{
public void m() {
int b = a;
}
public static void main(String[] args) {
}
}
You are mixing two concepts here:
1) accessing static variables from non-static context
2) protected access modifier
in java you can access protected members through inheritance or only within the same package.
Try accessing noCar here:
class Car{
int noCar = 9;
public static void main(String[] args) {
int b = noCar; // cannot make a static reference to a non static field warning error shown by eclipse
}
}
EDIT: considering packages
package com.bmw;
import com.car.*;
public class BMW extends Car {
public static void main(String[] args) {
System.out.println(new BMW().carNo);
Car car = new Car();
// Car has no idea that BMW is the child class
// and since it is not public we cannot access it directly
//can be accessed like this
car.getCarNo();
// you can do this because BMW has the variable carNo because of it extending Car
BMW bmw = new BMW();
int a = bmw.carNo;
}
}
package com.car;
public class Car {
protected int carNo=10;
public int getCarNo() {
return carNo;
}
public void setCarNo(int carNo) {
this.carNo = carNo;
}
}
The reason being the keyword "static".
Static associates the variable with the class and the not the instance. Since the class is public , all it's static variables will also be public i.e. all the variables will be accessible from other classes.
Also BMW extendsCar. Hence it will always be visible to BMW.
Yes, that is weird. In order to shed some light on this behaviour, it may be helpful, first of all, to recap how the protected modifier works in the absence of the static keyword, and why it works the way it does.
If class T declares a protected member m, then T and any class belonging to the same package as T can access the member, i.e. can say t.m; the type of the reference (t) must be T or a subclass of T. Additionally, any subclass U of T outside T's package can say t.m; in this case, the type of t must be U or a subclass of U.
The final part of this statement contains an important restriction. Its motivation is succintly explained in section 3.5 of The Java Programming Language (fourth edition) by Arnold, Gosling and Holmes:
The reasoning behind the restriction is this: Each subclass inherits the contract of the superclass and expands that contract in some way. Suppose that one subclass, as part of its expanded contract, places constraints on the values of protected members of the superclass. If a different subclass could access the protected members of objects of the first subclass then it could manipulate them in a way that would break the first subclass's contract -- and this should not be permissible.
Let's try to better understand this explanation by putting your Car and BMW classes to work. The following is a modified version of Car. I replaced the carNo field with an equally protected, but non-static, color field. The class also declares an obvious public getter/setter pair.
package com.car;
import java.awt.Color;
public class Car {
protected Color color;
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
Here is the BMW class, which at the moment does nothing but inherit Car's members.
package com.bmw;
import com.car.Car;
public class BMW extends Car {
}
Finally, let's add another subclass of Car.
package com.ferrari;
import com.car.Car;
import java.awt.Color;
public class Ferrari extends Car {
public Ferrari() {
color = Color.RED;
}
#Override
public void setColor(Color color) {
log("Nope. I'm proud of my color.");
}
...
}
As you can see, in our application Ferrari objects show an exclusive preference for a certain color (which is almost true in the real world, too). The color field is set in the constructor, and made read-only by a straightforward override of setColor(). Notice, by the way, that direct access to the color protected member is permitted here because the reference (an implicit this) is of the right type, that of the accessing subclass (Ferrari plays the role of U in the above description).
Now, suppose that BMW objects want to demonstrate their superiority over other cars, so they ask the class's programmer to be enhanced by means of a bold overtake() method. The programmer obliges.
...
public class BMW extends Car {
public void overtake(Car car) {
log("Wow! Become green with envy!");
car.setColor(Color.GREEN);
}
...
}
But, reading the application logs, the programmer soon discovers that, while this works fine with other cars, Ferrari objects stubbornly resist any insolence. He then, urged by BMW objects to find a solution, tries to by-pass the setColor() method...
...
public class BMW extends Car {
public void overtake(Car car) {
log("Wow! Become green with envy!");
car.color = Color.GREEN; // <-
}
...
}
... which is exactly what we can't do in Java. The Ferrari subclass's expanded contract places a constraint on the value of the color protected member. If the BMW subclass could directly access the color field through a Car (or Ferrari) reference, it would be able to break that contract. Java does not allow this.
So, this is why the protected modifier behaves the way it does when applied to non-static members. With protected static members, things change altogether. If the color field were static, any method inside BMW could directly access it. In your code, the BMW class accesses the carNo field without a hitch.
In the example above, the Ferrari class can restrict the possible values of the color field by overriding the instance setColor() method, which effectively amounts to changing, without violating, the superclass's contract.
Now, Java is, by design, a class-based object-oriented language, which does not have a concept of class object in the same sense as, for example, Objective-C. In Objective-C, classes are, literally, objects, and class methods (analogous, but non identical, to Java static methods) are, so to speak, instance methods of the class object -- with all the consequences of this fact: in particular, they can be overridden and used as polymorphic operations, the array class method in NSArray and NSMutableArray being an obvious example.
In Java, there is no class object -- an instance of java.lang.Class is by no means the same thing as an Objective-C class object. Static methods are, in essence, functions with an associated namespace. Most importantly, they can be inherited, but can't be overridden -- only hidden, just like static and non-static fields. (By the way, this means that invoking a static method is more efficient than calling an instance method, because not only its form, but also its implementation can be chosen at compile-time.)
But, and this is the end of the story, if static members cannot be overridden, they cannot really change the superclass's contract either. And, if they cannot change the superclass's contract, a subclass cannot break the contract of a different subclass by only accessing the latter's static members. If we recall that avoiding this kind of violations was precisely the reason of the restriction concerning protected non-static members, we can now understand why the designers of Java ended up lifting that restriction for protected static members. Once again, we can find a concise allusion to this line of thought in a short passage from section 3.5 of The Java Programming Language:
Protected static members can be accessed in any extended class... This is allowed because a subclass can't modify the contract of its static members because it can only hide them, not override them -- hence, there is no danger of another class violating that contract.
In java access modifiers and inheritance topic says below 4 points. What does "more private" mean in 3rd point ?
...
...
Methods declared without access control => can be declared more private in subclasses
...
Methods declared without access control => can be declared more private in subclasses
It is WRONG. This is exactly the reverse of the case. Methods declared with any level of access control must be overridden with that level or a more public level: in this case, the access level base class is 'default', so you can override with public or protected.
Contrary to what the Google documentation says, you cannot override with private. See JLS §8.4.8.3:
The access modifier (§6.6) of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:
If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.
If the overridden or hidden method is protected, then the overriding or hiding method must be protected or public; otherwise, a compile-time error occurs.
If the overridden or hidden method has package access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs.
(This has a translation in Russian on RU.SO)
There's actually no such term as 'more' or 'less private'. Instead 'more / less visible' is used.
The statement in the question is wrong. A method cannot be made less visible as that would break the Liskov substitution principle:
Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.
Here's a repo on GitHub that illustrates all possible variants with inheritance of a package-access method in Java.
https://github.com/NickVolynkin/PackageAccessTest
public class Parent {
//package access
void foo() {
}
}
public class ChildPublic extends Parent {
// Legal
#Override
public void foo() {
}
}
public class ChildProtected extends Parent {
// Legal
#Override
protected void foo() {
}
}
public class ChildPrivate extends Parent {
// Illegal
/*
#Override
private void foo() {
}
*/
}
public class SamePackageAccessTest {
{
new Parent().foo();
//these have overriden foo()
new ChildPublic().foo();
new ChildProtected().foo();
//this one had not overriden foo()
new ChildPrivate().foo();
}
}
package otherpackage;
import test.*;
public class OtherPackageAccessTest {
{
//Legal!
new ChildPublic().foo();
//illegal
/*
new ParentPackage().foo();
new ChildProtected().foo();
new ChildPrivate().foo();
*/
}
}
Full information can be found in this Java Tutorial
Methods declared without access control can be redefined (overridden is not quite the correct word here) in child classes that are not in the same package.
package p1;
public class A {
void m() {}
}
package p1;
public class B {
//This does not work as class is in the same package and this would be an attempt to reduce visibility
private void m() {}
}
package p2;
public class C extends A {
//This works fine as class C does not 'see' the parent method
private void m() {
}
}
This question already has answers here:
What is the difference between public, protected, package-private and private in Java?
(30 answers)
Closed 7 years ago.
Why can't I use protected constructors outside the package for this piece of code:
package code;
public class Example{
protected Example(){}
...
}
Check.java
package test;
public class Check extends Example {
void m1() {
Example ex=new Example(); //compilation error
}
}
Why do i get the error even though i have extended the class?
Please explain
EDIT:
Compilation error:
The constructor Example() is not visible
Usually protected means only accessible to subclasses or classes in the same package. However here are the rules for constructors from the JLS:
6.6.2.2. Qualified Access to a protected Constructor
Let C be the class in which a protected constructor is declared and
let S be the innermost class in whose declaration the use of the
protected constructor occurs. Then:
If the access is by a superclass constructor invocation super(...),
or a qualified superclass constructor invocation E.super(...), where E
is a Primary expression, then the access is permitted.
If the access is by an anonymous class instance creation expression
new C(...){...}, or a qualified anonymous class instance creation
expression E.new C(...){...}, where E is a Primary expression, then
the access is permitted.
If the access is by a simple class instance creation expression new
C(...), or a qualified class instance creation expression E.new
C(...), where E is a Primary expression, or a method reference
expression C :: new, where C is a ClassType, then the access is not
permitted. A protected constructor can be accessed by a class instance
creation expression (that does not declare an anonymous class) or a
method reference expression only from within the package in which it
is defined.
As an example, this does not compile
public class Example extends Exception {
void method() {
Exception e = new Exception("Hello", null, false, false);
}
}
but this does
public class Example extends Exception {
Example() {
super("Hello", null, false, false);
}
}
and so does this
public class Example {
void method() {
Exception e = new Exception("Hello", null, false, false) {};
}
}
So the rules are clear, but I can't say I understand the reasons behind them!
protected modifier is used only with in the package and in sub-classes outside the package. When you create a object using Example ex=new Example(); it will call parent class constructor by default.
As parent class constructor being protected you are getting a compile time error. You need to call the protected constructor according to JSL 6.6.2.2 as shown below in example 2.
package Super;
public class SuperConstructorCall {
protected SuperConstructorCall() {
}
}
package Child;
import Super.SuperConstructorCall;
public class ChildCall extends SuperConstructorCall
{
public static void main(String[] args) {
SuperConstructorCall s = new SuperConstructorCall(); // Compile time error saying SuperConstructorCall() has protected access in SuperConstructorCall
}
}
Example 2 conforming to JLS 6.6.2.2:
package Super;
public class SuperConstructorCall {
protected SuperConstructorCall() {
}
}
package Child;
import Super.SuperConstructorCall;
public class ChildCall extends SuperConstructorCall
{
public static void main(String[] args) {
SuperConstructorCall s = new SuperConstructorCall(){}; // This will work as the access is by an anonymous class instance creation expression
}
}
In fact you are already using protected constructor of Example because Check has an implicit constructor and implicit Example constructor call:
public Check() {
super();
}
I am preparing for the SJCP 6, and I found a detail I had not seen so far for accessing a protected member from a subclass of the subclass for the class where the member is declared. I am clear that a protected member can only be accessed from another package when we try to access it through inheritance, but what about a subclass of the subclass, can we still access it?
The book says:
Once the subclass-outside-the-package inherits the protected member,
that member (as inherited by the subclass) becomes private to any code outside
the subclass, with the exception of subclasses of the subclass.
My question is about the subclasses of the subclass, how those see the member, as protected also? Can they access it? Because it says the member becomes private to any code outside the subclass, with the exception of subclasses of the subclass, so, how do they see it?
If B is a subclass of A, and C is a subclass of B, then C is also a subclass of A and has access to A's protected members.
Variables, methods and constructors which are declared protected in a superclass can be accessed only by the subclasses in other package and also by subclass of subclasses
or any class within the package of the protected members' class.
i just created an example in eclipse for this case go and try it ..
For eg
Class MyClass in package test have a method protected named get method
package test;
public class MyStaticClass {
protected int getmethod(){
int a=0;
return a;
}
}
Class A in same package extends MystaticClass and the protected method is accessible there
package test;
public class A extends MyStaticClass{
#Override
protected int getmethod() {
// TODO Auto-generated method stub
return super.getmethod();
}
}
Now class B extending A which is in another package can also access the same method
package testing;
import test.A;
public class B extends A{
#Override
protected int getmethod() {
// TODO Auto-generated method stub
return super.getmethod();
}
}
Now class c extending B again in another package also can access it..
package testinggg;
import testing.B;
public class c extends B{
#Override
protected int getmethod() {
// TODO Auto-generated method stub
return super.getmethod();
}
}
So it is accessible in subclasses of sublclasses in another package
I am reading Thinking In Java at the moment and I encountered one small problem. I am doing exercise 12 from chapter 8.
Create an interface with at least one method, in its own package. Create a class in a >separate package. Add a protected inner class that implements the interface. In a third >package, inherit from your class and, inside a method, return an object of the protected >inner class, upcasting to the interface during the return.
So I created these .java files:
A.java
package c08;
public interface A
{
void one();
}
Pr2.java
package c082;
import c08.*;
public class Pr2
{
protected class InPr2 implements A
{
public void one() {System.out.println("Pr2.InPr2.one");}
protected InPr2() {}
}
}
Ex.java
package c083;
import c082.*;
import c08.*;
class Cl extends Pr2
{
A foo()
{
InPr2 bar=new InPr2();
return bar;
}
}
And my NetBeans IDE underlines
InPr2();
and says that:InPr2() has protected access in C082.Pr2.InPr2 and I am wondering why.
If I didn't explicitly state that constructor in InPr2 should be protected it would be only accessible in C082 package, but when I am inheriting class Pr2 shoudn't it be available in class Cl, because InPr2 is protected? Everything is fine when I change constructor to public.
The constructor of InPr2 is protected, meaning that only classes inheriting from InPr2 (not Pr2) can call it. Classes that inherit from Pr2 can see the class Pr2, but they can't call its protected members, like the protected constructor.
It should work just fine as you have it, except changing the protected InPr2() {} to public InPr2() { }. In other words "Anyone can instantiate this class IF they can see the class to begin with."
Even though the class InPr2 is accessible in Cl, its constructor is not. A protected constructor is accessible only to subclasses and classes in the same package.
Change:
Pr2.java
package c082;
import c08.*;
public class Pr2
{
protected class InPr2 implements A
{
public void one() {System.out.println("Pr2.InPr2.one");}
// This constructor was available only
// to a class inheriting form Pr2.InPr2 - protected InPr2() {}
public InPr2() {}
}
}
The constructor fromPr2.InPr2 was just available to a class if it extended Pr2.InPr2.
Protected member variables, methods and constructors are not accessible outside the package unless they are inherited.
When we try to create an object of InPr2 the compiler will show error as the protected constructor is not accessible outside the package.
The creation of an object depends on the access modifier of the Constructor too.
You can do one thing: InPr2 can be inherited inside class C.
no class in java can be protected.