I have the following code in Java:
package a;
public classs ClassInOtherPackage{
protected void protectedMethod(){}
protected class protectedInnerClass {}
}
package b;
import a.*;
public class MyClass extends ClassInOtherPackage{
public MyClass(){
MyClass x = new MyClass();
x.protectedMethod(); //<-- This one ok
//UPDATED: Declaration is ok
MyClass.protectedInnerClass y; //<-- This one ok
//UPDATED: Only when instantiated is not allowed, why?
y = x.new protectedInnerClass(); //<-- Not allow when instantiated.
}
}
Refer to the Java 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."
Why can't I instantiate the inner protected class as shown above?
In JLS 8.8.9
8.8.9. Default Constructor
... if the class is declared protected, then the default constructor is implicitly given the access modifier protected (§6.6); ...
So the implicitly declared constructor is:
protected class protectedInnerClass {
protected protectedInnerClass(){
super();
}
}
You code won't compile because the constructer is inaccessible.
The default constructor of protectedInnerClass is protected , not the class . You need to define a public constructor to your inner class :
protected class protectedInnerClass {
public protectedInnerClass () {}
}
MyClass can access the protected members of ClassInOtherPackage , but it cannot access the protected members of protectedInnerClass , since its constructor is protected hence you get such a compilation error.
As johnchen902 said the default constructor of a protected class is implicitly protected.
Protected means that only subclasses and classes within the same package can access it.
The protectedInnerClass doesn't declare a constructor thus it is implicitly protected.
MyClass is not a subclass of protectedInnerClass, thus it can not access it.
So you have to make it public or you can modify your code like this:
public class MyClass extends ClassInOtherPackage {
public MyClass() {
MyClass x = new MyClass();
x.protectedMethod(); // <-- This one ok
MyClass.protectedInnerClass y = x.new MyProtectedInnerClass();
}
protected class MyProtectedInnerClass extends protectedInnerClass {
}
}
Related
I'm new to java and getting the hang of protected visibility.
I have Class A which has protected method method1 as follows -
public abstract class A {
public A(...){}
protected void method1(){
// do something
}
Now I have another Class B which extends a different Class C. Class B has a nested static class, Class D extending Class A
public class B extends C {
public B(...){
super(...);
}
private static class D extends A {
D(...){super(...);}
}
public void method2() {
D record = new D();
record.method1(); // need to access the protected method1 of class A, which is the superclass of nested class D. Getting the error here
}
}
I get this error - method1 has protected access in Class A
Now my question is how can I access method1? I cannot change it to public in class A
You need to create a proxy method in class D as outlined below. Class D can access Class A's protected methods, but an instance of Class D can't call protected methods directly, and must have a proxy method to call the protected method of the super class.
In class D, you need to create a public getter for the method in Class A, so:
public class A {
protected void protectedMethod() {}
}
public class D extends A {
public void callProtectedMethod() {
super.protectedMethod();
}
}
final D record = new D();
record.callProtectedMethod();
Since A.method1() is protected, it is only accessible from same class/same package/child of A.
In your code, your are calling A.method1() in B, that is not accessible if B not in same package as A
The solution is using a wrapper as #Alex Ander or change modifier of A.method1() to public
I have two classes
package a;
public class A {
protected void doSomething() {
}
protected static class C {
protected C(int c) {
}
}
}
package b;
public class B extends A {
#Override
protected void doSomething() {
C c = new C(0); //compile error
C c2 = new C(0){}; //legal
}
}
I have read chapter 6.6.2.2. Access to a protected Constructor of JLS (https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html) but i am still confused with the explanation. What is wrong with the call of the super constructor new C(0); even if B is a child of A?
Thank you :-)
Variables, methods, and constructors, which are declared protected in a superclass can be accessed only by the subclasses in other package or any class within the package of the protected members' class.
Now, the constructor of C class is protected therefore is accessible outside the a package only by subclasses of C. But B is not a subclass of C ...
As #Amongalen pointed out, the second statement
C c2 = new C(0){};
is legal because it creates an anonymous class that extends C, therefore the protected constructor is visible here.
Why can't we instantiate a class with a protected constructor if its child is in a different package? If protected variables and methods can be accessed, why doesn't the same rule also apply for a protected constructor?
pack1:
package pack1;
public class A {
private int a;
protected int b;
public int c;
protected A() {
a = 10;
b = 20;
c = 30;
}
}
pack2:
package pack2;
import pack1.A;
class B extends A {
public void test() {
A obj = new A(); // gives compilation error; why?
//System.out.println("print private not possible :" + a);
System.out.println("print protected possible :" + b);
System.out.println("print public possible :" + c);
}
}
class C {
public static void main(String args[]) {
A a = new A(); // gives compilation error; why?
B b = new B();
b.test();
}
}
According to the Java Spec (https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.2)
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.
In your case, access to the protected constructor of A from B would be legal from a constructor of B through an invocation of super(). However, access using new is not legal.
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...
6.6.7 Example: protected Fields, Methods, and Constructors Consider
this example, where the points package
declares:
package points;
public class Point {
protected int x, y;
void warp(threePoint.Point3d a) {
if (a.z > 0) // compile-time error: cannot access a.z
a.delta(this);
}
}
and the threePoint package declares:
package threePoint;
import points.Point;
public class Point3d extends Point {
protected int z;
public void delta(Point p) {
p.x += this.x; // compile-time error: cannot access p.x
p.y += this.y; // compile-time error: cannot access p.y
}
public void delta3d(Point3d q) {
q.x += this.x;
q.y += this.y;
q.z += this.z;
}
}
which defines a class Point3d. A
compile-time error occurs in the
method delta here: it cannot access
the protected members x and y of its
parameter p, because while Point3d
(the class in which the references to
fields x and y occur) is a subclass of
Point (the class in which x and y are
declared), it is not involved in the
implementation of a Point (the type of
the parameter p). The method delta3d
can access the protected members of
its parameter q, because the class
Point3d is a subclass of Point and is
involved in the implementation of a
Point3d. The method delta could try to
cast (§5.5, §15.16) its parameter to
be a Point3d, but this cast would
fail, causing an exception, if the
class of p at run time were not
Point3d.
A compile-time error also occurs in
the method warp: it cannot access the
protected member z of its parameter a,
because while the class Point (the
class in which the reference to field
z occurs) is involved in the
implementation of a Point3d (the type
of the parameter a), it is not a
subclass of Point3d (the class in
which z is declared).
I agree with previous posters, don't know why you would want to do this (instantiate parent in that way in extending class) but you could even do something like this:
public void test() {
A obj = new A(){}; // no compilation error; why? you use anonymous class 'override'
...
Why do you need A obj=new A(); in class, whereas object of class b is itself an object of class A
And in class c it is giving error because, you are accessing the protected property of class A which is constructor.
To get object of class A in this case you must use this function in class A
static A getInstance()
{
A obj = new A(); // create obj of type A.
return obj; // returns that object by this method. No need to use 'New' kind of instantiation.
}
If protected variables and methods can be accessed, why doesn't the same rule also apply for a protected constructor?
Protected variables and methods can only be accessed if the child class in another package extends the class containing the protected variables and methods.
You are able to access variable 'b' in child class B because you have extended the class A. You will not be able to access variable 'b' in class C as it is not extending class A.
The only way to access protected constructor in child class is by using parent class reference variable and child class object.
package pack2;
import pack1.A;
class B extends A {
public void test() {
A obj = new B(); // will execute protected constructor
System.out.println("print protected possible :" + b);
}
}
I have a base class and subclass. Base class has common methods and its implementation which I want to use in subclass but I want to use subclass member variable instead of superclass. I do not want to rewrite the same method in subclass. Is there a way in Java to achieve this.
You could create a protected setter on the member variable & then override the value of the super's variable within the constructor of the subclass:
class Animal {
private String voice = "Oooo";
protected void setVoice(String voice) {
this.voice = voice;
}
public void speak() {
System.out.println(this.voice);
}
}
class Dog extends Animal {
public Dog() {
setVoice("woof");
}
}
You can use a method to access the member and override it in subclasses.
Class A{
public void DoStuff(){
int aux = getResource;
/*cool things with aux*/
}
protected int getResource(){
return internal_member;
}
private int internal_member;
}
Class B extends A{
private int another_member;
#Override
public int getResource(){
return another_member;
}
}
But take into account that this will not prevent people chaging class A from using the member directly, It might be better to create a base class for the members and the getters.
Another Option, as some people outlined before is to have the data member in the base class as protected and initialize it in the subclass:
Class A{
public void DoStuff(){
/*cool things with internal_member*/
}
protected List internal_member;
A(){internal_member = /*Set here a value*/}
}
Class B extends A{
B(){internal_member = /*Set a different value here! you can even declare a member and assign it here*/}
}
You can use constructors with arguments if you need.
I am learning about access levels in java and I have created 3 classes:
In package my.inheritance
I have class A and class C
package my.inheritance;
public class A {
protected int a=15;
}
package my.inheritance;
public class C {
public static void main(String[] args)
{
A a = new A();
System.out.println(a.a);
}
}
And in another package called my.inheritance.test I have a class B trying to access protected field of int value a but the compiler complains for this!
package my.inheritance.test;
import my.inheritance.A;
public class B extends A{
public static void main(String[] args)
{
A a = new A();
int value = a.a;
System.out.println(value);
}
}
I was under the impression with protected you can access a member from a different class in a different package as long as you subclass it! Why the visibility error then ?
Every method can access protected fields of its own class, and all its parent classes. This does not include access to protected fields of another class, even if they have the corresponding base class in common.
So methods in class B can access protected fields from objects of class B, even if they were declared in A, but not from some other object of class A.
One could say that class B inherits the protected members from A, so now every B has those members as well. It doesn't inherit access to the protected members of A itself, so it cannot operate on protected members of any A but only on those of B, even if they were inherited from A.
Try:
public class B extends A
{
public static void main(String[] args)
{
B a = new B();
int value = a.a;
System.out.println(value);
}
}
You can access a only if it is in the same object.
1. protected is an access modifier which is used when you want to have an access outside the package.
2. Most people try to access the protected member of the Super class by creating and Object reference variable of the Super class, and then using dot operator to access that protected member.... But thats WRONG.
3. We get access to the inherited member of the Super class Not the direct member of the super class.
Eg:
package com.demo1;
public class A{
protected int a = 5;
}
package com.demo2;
public class B extends A{
public static void main(String[] args){
System.out.println(new B().a); // This "a" is the inherited member
}
}
4. And one more important point, This inherited "a" member in the sub-class, will be seen by the another class in the same package that of the sub-class as a private member.. So consider that another class in this package can't even see this protected memeber...
You have access to this field from B using this.a because B extends A, but in this case you are trying to access to this field througth an instance of A, this is limited by the protected access.
What you're trying to do is:
A a = new A();
int value = a.a;
Note that a.a is a qualified name, and in this case you can call it in body of a class B only if the type of the expression to the left of . is B or it's subclass.
Relevant part of JLS