package pack1;
class A{
protected void m1(){
System.out.println("protected modifier");
}
}
package pack2;
class B extends A{
public static void main(string[]args){
B b = new B();//Valid
b.m1();
A a = new B();//Invalid
a.m2();
A a1 = new A();//InValid
a1.m1();
}
}
Why while accessing protected members outside package we need to have child class reference only.?
Why we cant use parent reference to access protected members (Here A a = new B())?
I have gone through blogs and many stack overflow answers but didn't find any answer for WHY?.
so can anyone help me knowing the answer for WHY?
You are not allowed to access A because you are still outside of a subclass or package. The main method is static, thus unbound from instances of the B class. In order to access A you need to be inside the B class, so in a non-static context like
public class B extends A {
public void foo() {
m1(); // Valid call since inside subclass
}
}
I think you have misunderstood what static means.
The details of protected are described in the Java Language Specification. Extract from JLS§6.6.2:
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.
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.
The limitation even goes beyond your example. The key is "responsible for the implementation". Compare that to the following example:
package a;
public class Point {
protected int x;
protected int y;
}
package b;
import a.Point;
public class Point3D extends Point {
public void delta(Point other) {
other.x += this.x; // Compile-time error: Cannot access other.x
other.y += this.y; // Compile-time error: Cannot access other.y
}
}
Though the class Point3D is a subclass of Point, it is not responsible for the implementation of the other object. Thus, it is not allowed to access its protected members.
Same for
public class B extends A {
public void foo() {
A other = new A();
other.m1(); // Compile-time error
}
}
since the current instance to which the foo() method call belongs to is not responsible for the implementation of other. Thus, access is not permitted.
The concept of inheritance/polymorphism makes the inherited public and protected methods and variables of the parent class - members of the child class and is therefore accessible to the objects of the child class. protected access requires two rules-
can only be accessed by classes that are within the same package
can be accessed via inheritance.
A a = new B();
a.m1(); //doesn't compile
This is an instance of the B class but as far as it is a reference of A, it is an A object. That is why the object "a" only has access to members that are common to A and B. i.e object "a" as a reference of class A has access only to the inherited methods of class B. It does not have access to any method or class variable of B that is absent in A even though it is an instance of class B. You have to explicitly cast it to a B to give it access to unique methods & variables of class B. So, bearing this in mind, as far as Java is concerned, object "a" is a class A object that is in another package. Therefore even though the method a.m1 was inherited, "a" does not have access to it because it is an A object in another package. a.m1 will compile in pack1.
Contrast that with this code
B b = new B();
b.m1() //compiles
b is an object of B and therefore rule 2 of the protected access applies. Since m1 is an inherited protected method of the object B, it has full access to it.
Related
I have a Super-class A in PackageOne and a Sub-class B which is in PackageTwo.
package PackageOne;
public class A {
protected number = 0;
}
Second Class is here
package PackageTwo;
public class B extends A {
public static void main(String args[]) {
A a = new A();
System.out.println(a.number);// Here is the error occurs
}
}
Error is The field Person.name is not visible;
As I know a protected member can be accessed by a super-class reference, but why the error occurs.
If you are in a different package, you can't access the field of another instance. You can only access the field within yourself.
Class A:
package a;
public class A {
protected int i;
}
Class B:
package b;
public class B extends A {
void m() {
A a = new A();
System.out.println(a.i); // error here!
System.out.println(i); // but no error here
}
}
If A and B were in the same package, though, there would be no error whatsoever.
Controlling Access to Members of a Class
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.
Because it is protected member. You need to extend (inheritance) the class to access the protected members of a class in another package.
Instead of accessing via A access it via B. Once you extend the class A it becomes the part of class B. You cannot access it using the reference of A.
public class B extends A {
public static void main(String args[]) {
B b = new B(); // create the instance of B.
System.out.println(b.number); // access via the b.
}
}
You are also missing the data type in class A:
public class A {
protected int number = 0;
}
In the same package you can reference the members using the instance reference. Check the below code:
package PackageOne;
public class C {
public static void main(String[] args) {
A a = new A();
System.out.println(a.number); // this works.
}
}
Protected methods can only be accessible through inheritance in subclasses outside the package. And hence the second approach tryMeProtected(); works.
The code below wont compile because we are not calling the inherited version of protected method.
Example
Class1 c = new ClassA();
c.tryMeProtected(); // ERROR: tryMeProtected() has protected access in ClassA
Follow This stack link for more explaination.
That's not how inheritance works. You don't make a class a subclass of another one by creating an instance of it.
You have to extend it.
public class B extends A
This will allow you to access protected fields. However, you will have to import PackageOne.A to do this.
EDIT
See this SO answer by #David Segonds on how these keywords work
| Class | Package | Subclass | World
————————————+———————+—————————+——————————+———————
protected | y | y | y | n
You have to be a subclass or in the same package to access these properties.
From the official documentation:
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.
(I keep re-reading that question title and thinking about how ridiculous it must look, but I assure you that is the best description of the problem, and I have an actual application where this is the best structure. I swear I'm not crazy.)
Consider the following. Each block is a separate file:
package myPackage;
public class A {
public int i;
public A(int i) {
this.i = i;
}
public class B {
}
}
package myPackage;
import myPackage.A.B;
public class Main {
public static void main(String[] args) {
class C extends B {
public C(A enclosingInstance) {
enclosingInstance.super();
}
public void show() {
System.out.println(A.this.i);
}
}
A myA = new A(2);
C myC = new C(myA);
myC.show();
}
}
Note that the enclosingInstance business is to solve a problem involving intermediate constructor invocations. See "Why can't outer classes extend inner classes?".
I would expect the output to be "2". But instead, I have a compile error on System.out.println(A.this.i);:
No enclosing instance of the type A is accessible in scope
I think the programmatic concept I'm trying to solve is sound: Create a new type of B inside main to give to A that uses things from A that types of B can access.
So what am I doing wrong, or why isn't this possible in java?
EDIT/UPDATE: Note that the same error appears when the code in main is moved to a non-static method. That is to say, I tried moving everything inside of static void main to a new, non-static method of class Main called go(). Then I changed static void main to the single line new Main().go();. The error is in the same spot. So it doesn't seem to be an issue of class C being defined in a static context.
You want A.this to refer to the enclosing instance of the B instance. But why should it? That's not what the syntax means. A.this would mean the enclosing A instance of the C instance, and this does not make sense because C is not an inner class of A.
To make this clearer, here is an example where C is an inner class of A.
public class A {
public int i;
public A(int i) {
this.i = i;
}
public class B {
void foo() {
System.out.println(A.this.i);
}
}
public class C extends B {
C(A a) {
a.super();
}
void bar() {
System.out.println(A.this.i);
}
}
public static void main(String[] args) {
A a1 = new A(1);
A a2 = new A(2);
C c = a1.new C(a2);
c.foo();
c.bar();
}
}
Here C extends B, and both C and B are inner classes of A. Therefore any C has an enclosing A instance, and it also has an enclosing A instance when considered as a B, and these enclosing instances are different (as proved by the fact that foo and bar print different numbers).
So, A.this could not possibly mean what you want it to mean, because it already means something else. I guess the reason why the language designers didn't come up with other syntax to mean the enclosing instance of a super class, is because such syntax would be very complicated, with little pay-off (simple workarounds already exist).
This is absurd code that you should never write for production.
It is, in part, explained in the documentation for Explicit Constructor Invocations
Qualified superclass constructor invocations begin with a Primary
expression or an ExpressionName. They allow a subclass constructor to
explicitly specify the newly created object's immediately enclosing
instance with respect to the direct superclass (§8.1.3). This may be
necessary when the superclass is an inner class.
All this to say that C is a local class (which is an inner class, which is kind of nonsense because if you declare it in a static method there is no enclosing instance) that is a subclass of B but not a nested class of A. As such, there is no enclosing instance. An instance of C does not have an enclosing instance. (Though it would if you declared it in an instance method, but that would be an instance of Main.)
The newly created object's immediately enclosing instance (from JLS) is specified indirectly through a constructor parameter.
You'd have to store it yourself
private A enclosingInstance;
public C(A enclosingInstance) throws CloneNotSupportedException {
enclosingInstance.super();
this.enclosingInstance = enclosingInstance;
}
and since A#i is public, you can access it normally
public void show() {
System.out.println(enclosingInstance.i);
}
With the provided information, I would do this :
public class B {
protected A getOuterInstance() {
return A.this;
}
}
and just let C inherit and use this method. I know you dislike this method but this is the simplest answer I can see. With more information, I would probably propose a design which would try not involving any inner class as this is not a normal use case for inner classes.
I have 3 class A, B, C :
package com.training.protectedclass.A;
public class A
{
protected int value;
}
package com.training.protectedclass.B;
import com.training.protectedclass.A.A;
public class B extends A
{
public void test()
{
this.value = 10;
A a = new A();
a.value = 12; //Error => The field A.value is not visible
}
}
package com.training.protectedclass.C;
import com.training.protectedclass.B.B;
import com.training.protectedclass.A.A;
public class C extends A
{
public void test()
{
B b = new B();
b.value = 45; //Error => The field A.value is not visible
}
}
When the inherited class exists in different package than the base class, it can't access the protected member of base class. But when all the three class exist in the same package the above errors disappear and the code is compiled without errors.
Can anyone explain me the cause of each error launched in my code above?
Thanks :)
This is because protected in Java means two things: 1) inherited classes can see protected members that they inherit, and 2) other classes in the same package can see protected members (even if they don't inherit the member).
So in class B you have inherited value and thus you can access it via this.value, but as class A is in another package you can't see a.value. This is because when you call a.value you are accessing a member of a class in another package rather than the inherited version of the field value.
In the case of class C, you can't access any protected member of B because you neither inherit from B nor are in the same package as B.
The Java Language Specification defines the protected access modifier this way:
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.
When you have this.value = 10;, the B object accesses to one of its own members, which is a protected field declared in the superclass. On the other hand, when you have new A().value, the B object tries to access a protected member of an object that it doesn't implement.
Documentation in http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html says this.
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.
But your problem is, you are trying to access a protected member of a different object than this. Check this one out http://bmanolov.free.fr/javaprotection.php
I think JLS 6.6.2.1 gives the answer:
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.
You're accessing the member value in the body of B. Therefore, for applying this clause, S is B, and according to the last paragraph, when you try to access E.value for some expression E, the access is permitted only if the type of E is B or a subclass of B. Since the type is A, which isn't a subclass of B, this condition fails.
Are fields only inherited "one level up"?
By that I mean that if I have a Superclass to a Class, which then has a Subclass, and the Superclass has a field, the Class will inherit it and the Subclass won't. Is this correct?
And if it is, is there a way to make the Subclass automatically inherit the field from the Superclass given that, as I understand it, there's no way to inherit from two classes at once?
Thank you to anyone who takes the time to answer. I realize my question may be impractical and in reality you'd probably just override the field or something, but I'm not trying to do anything specific, just trying to learn how Java works. Thank you.
Here's my code:
public class SuperClass {
protected int entero;
protected void method(){
entero=1;
}
public class SubClass extends Class {
public SubClass(){}
}
public class Class extends SuperClass {
public Class(){}
}
public static void main(String[] args){
Class object= new Class();
SubClass subobject= new SubClass();
/*This is where I get an error, why?*/
subobject.entero=2;
/*This one is fine*/
object.entero=2;
object.method();
System.out.println(object.entero);
}
Any class B than extends a class A, will inherit A's fields. If a class C extends B, C will inherit all non-private instance fields and methods from A and B, ie transitivity holds.
If a field is private, then one cannot directly change it from a subclass; however, you can get around this by using setter/getter methods.
If a field is protected, then a subclass has direct access to it.
EDIT 1:
In a comment you say that the field is protected, but you still can't access it from a subclass. The only thing I can think of is that you have a situation like this:
class A
{
protected int x;
}
class B extends A
{
private int x;
}
class C extends B
{
private int z = x;
}
This would NOT work because by declaring x again in B, you are hiding the x field from A. So, now C sees x as B's private variable x, which you do not have access to.
EDIT 2:
I'm not going to remove the above edit, because it's informative, but now that you posted your code, it's because your SubClass does not actually extend anything (this was later fixed in an edit).
Inheritance in Java is transitive.
If your classes are Superclass < Class < Subclass, then Subclass inherits all the non-private instance fields and methods provided by Superclass not overridden or hidden by Class or Subclass.
One level of inheritance is specified by the Java Language Specification, section 8.4.8: Inheritance, Overriding and Hiding:
A class C inherits from its direct superclass and direct superinterfaces all abstract
and non-abstract methods of the superclass and superinterfaces that are public,
protected, or declared with default access in the same package as C, and are neither
overridden (§8.4.8.1) nor hidden (§8.4.8.2) by a declaration in the class.
If you have classes that are:
public class SuperClass {
public void methodName() {}
//SuperClass's stuff
}
public class MidClass extends SuperClass {
//MidClass's stuff
}
public class SubClass extends MidClass {
//SubClass's Stuff
}
Then it is perfectly valid to have in your main method:
SubClass sc = new SubClass();
sc.methodName();
I have an question which comes under multilevel inheritance in Java. All Three Classes are in Same package
I have class A :
public class A {
protected int x;
}
public class B extends A {
public void doSomething {
// x is visible.agreed, as it is a direct subclass of A
}
}
public class C extends B {
public void doSomething {
// x is still visible, how come? I mean it is at the 2nd level
// I am confused why?
}
}
does it like have any significance? or it is behavior which we have to take it by default?
variable/methods marked with protected modifier are visible to all the classes in the same pacakage and only to subclasses in different packages.
below are the example cases.
package a;
class A{
protected int x;
}
class B extends A{
//x can be accessed from this class
}
class C extends B {
//x can be accessed from this class
}
class D{
//x can be accesed this class but you will have to create A's instance
}
package B
class One {
//cannot access x from this class
}
class Two extends A {
//can access x from this class
}
The access level modifiers in Java are:
public - visible to all code
protected - visible to all code in the same package and to subclasses regardless of package
nothing (default) - visible to all code in the same package
private - visible only to code in the same class (including nested classes)
See, for instance, the Java tutorial Controlling Access to Members of a Class or (for lots of technical details) section 6.6 of the Java Language Specification.
Definition of the keyword
Protected
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.
I suggest you read this.
The Java protected keyword works its way down to all subclasses (and members of the package). If there was a protected member in Object, any object could access it. By contrast, private is only visible to the local class (and inner classes), and public is accessible by all.
Have a look at this glossary, which shows in-depth how protected members and methods are inherited, and the Java documentation on inheritance.
You cannot restrict access to members in subclasses. This rule applies to methods (you can't override public method and make it private) but you can see analogy here. If the field is protected, it will be protected in every subclass, no matter how deep. Of course you can't override fields in Java, but just to give you an overview.
Please refer this: http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
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.
So if your class C shares the package with A and B, its accessible.
Inheritance is transitive: if class B inherits from class A;
and class C inherits from class B; then C is also a
subclass / child class / descendant of class A.