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
Related
I want to access a protected field of a super-class from a sub-class in Java:
Class Super {
protected int field; // field set to a value when calling constructor
}
Class B extends Super { // field of super class is set to value when calling
// constructor
}
Class C extends Super { // same here
}
B b = new B();
C c = new C();
b.super.field ?
The class can access the field directly, as if it were its own field. The catch is that the code doing the access must be in the code of the derived class itself, not in the code using the derived class:
class B extends Super {
...
int getSuperField() {
return field;
}
}
The protected modifier allows a subclass to access the superclass members directly.
But the access should be made inside the subclass or from the same package.
Example:
package A;
public class Superclass{
protected String name;
protected int age;
}
package B;
import A.*;
public class LowerClass extends SuperClass{
public static void main(String args[]){
LowerClass lc = new LowerClass();
System.out.println("Name is: " + lc.name);
System.out.println("Age is: " + lc.age);
}
}
From Javadoc:
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.
In either Super or B, create a getter method:
public int getField() {
return field;
}
Then you can do:
B b = new B();
int field = b.getField();
It's not allowed to access a protected field outside the body of the declaring and extending class.
See here 6.6.2 Access to a protected Member
A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object.
The solution would be any of the answers with a setter/getter or making it public.
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.
I have a base class A, having a method "say" that calls from constructor of A. All the heritable classes uses the method "say" like it is. But one of the classes need to redefine this method. How is it possible?
For sure, I can denote base method "say" as abstract, but in that way, i have to copy the same method "say" in all the heritable classes.
If i just redefine method without denoting base one as abstract, it is not gonna be called.
public abstract class A(){
public A(){
say(); // <- wanna call this method from heritable class, if its redefined.
}
protected void say(){};
}
public class B extends A(){
public B(){
super();
}
private void say(){};
}
refactoring 1
public abstract class A(){
public A(){
// constructor methods
}
protected void say(){};
protected void executeSay(){
say();
}
}
public class B extends A(){
public B(){
super();
executeSay();
}
#Override
protected void say(){};
}
First of all one must be made clear: calling an overridable method from a constructor is a well-known antipattern. It will almost certainly break your code because the subclass method will be invoked before the subclass constructor is done and so will observe an uninitialized object. Thus I should better refrain from giving you detailed advice on Java technicalities involved in achieving this antipattern.
The only safe way to acomplish your requirement is to let the construction finish and only afterwards call an initialize-kind of method. If you want to ensure initialize is always invoked, make the constructors non-public and provide a factory method instead.
Unfortunately, Java requires quite a bit of work on your part to make this work properly.
You cannot instantiate a abstract class. That saying you have to link the abstract class reference to the concrete inherited class.
eg. A a = new B();
If that's the case, and B have redefined the say() method, then the say method in B will be called.
public class TestPad {
public static void main(String[] args) {
A a = new B();
}
}
abstract class A {
public A() {
say();
}
public void say(){
System.out.println("A");
};
}
class B extends A {
public B() {
super();
}
public void say() {
System.out.println("B");
}
}
The output will be B
public class B extends A {
public B() {
super();
}
#Override
protected void say() {
// your diffent say code
};
}
I'm not sure if you are allowed to reduce visibility to private.
Because of polymorphic method invocation, in your case the B.say() will be invoked if you override it.
But as #sanbhat commented, you need to change visibility of say() to protected.
The following is my ProtectedConstructor.java source code:
package protectCon;
public class ProtectedConstructor{
public int nothing;
ProtectedConstructor(){
nothing = 0;
}
}
And following is the UsingProtectedCon.java source:
package other;
import protectcon.ProtectedConstructor;
public class UsingProtectedCon extends ProtectedConstructor{ //**Line 4**
public static void main(String... a) {
}
}
When I compile UsingProtectedCon.java, I get error at Line 4 shown above. It says that ProtectedConstructor() is not public ; so cannot be accessed outside package.
However, since my class is public, shouldn't I be able to extend it outside package. I am anyway not creating any instance of it.
Now, if I make the constructor of ProtectedConstructor class as public or protected then the code compiles fine with no error.
So then why is it necessary even for the constructor to be public or protected, and not just have default access?
If you want to extends a class outside its package it must have a constructor that is public or protected because in Java every constructor must call a constructor from its superclass.
Because of this there is an implied super() call in every constructor which does not have this() or an explicit call to super() as its first statement. And if you don't specify a constructor at all Java will add a default parameterless constructor, so in effect your code looks like this:
public class UsingProtectedCon extends ProtectedConstructor {
public UsingProtectedCon() {
super();
}
public static void main(String... a) {
}
}
So in other words your code is failing to compile because the call to super() in the default constructor cannot be resolved.
constructor is a member of class like field and method so access modifier applies to it in the same manner it apples to all the member of class
when you extend the class A in B , A's its default constructor will get called from B's constructor implicitly (if you don't call any of the overloaded constructor)
in your class ProtectedConstructor is defined with Package-Private access
This means that outside the package its not seen even by the classes that extend from your ProtectedConstructor class
Define your constructor with 'protected' access modifier instead and you'll be done:
package protectCon;
public class ProtectedConstructor{
public int nothing;
protected ProtectedConstructor(){
nothing = 0;
}
}
Your constructor is not public. Default scope is package-private.
JLS 6.6.7 answers your question. A subclass only access a protected members of its parent class, if it involves implementation of its parent. Therefore , you can not instantiate a parent object in a child class, if parent constructor is protected and it is in different package.Since the default constructor of the subclass would try to call parent class constructor ,you got this error.
See this SO Post for details
to avoid all confusion do it like this.
package protectCon;
public class ProtectedConstructor{
public int nothing;
public ProtectedConstructor(){
nothing = 0;
}
}
package other;
import protectCon.ProtectedConstructor;
public class UsingProtectedCon extends ProtectedConstructor{ //**Line 4**
public UsingProtectedCon(){
super();
}
public static void main(String... a){
}
}
You can have constructors which are public, protected (for internal used) and even private.
A simple example is String which has public constructors for general use and package-local constructors for internal use.
The ObjectOutputStream class has a public constructor which takes an OutputStream and a protected constructor which can only be used by a sub-class.
BTW: if you have an abstract class, does it make sense to make the constructor public as if often the case. ;) hint: it is the same as protected.
If child will have constructor which is private in parent,we can make child's instance with that constructor and cast it to parent's type.
So to prevent this java compiler is not allowing constructor to have constructor which is private in parent.
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.