Consider class test
package access;
public class test {
public String s;
protected test(String s){
this.s = s;
System.out.println("access.test constructor");
}
protected void test1(String s){
this.s = s;
System.out.println("access.test test1 method");
}
}
Consider class Operations
package data;
public class Operations extends access.test{
Operations(String s){
super(s);
}
public static void main(String args []) {
// TODO Auto-generated method stub
//Operations O = new Operations("Operations!");
access.test t = new access.test("hello");//1
t.test1("hi!"); //2
}
}
Constructor test and method test1 is not visible at lines 1 and 2. Why??
In your data.Operations.main() you are attempting to instantiate access.test via new:
access.test t = new access.test("hello");//1
You can't do that. That's what it's telling you via the error.
Section 6.6.1 of the JLS tells us:
A member (class, interface, field, or method) of a reference (class,
interface, or array) type or a constructor of a class type is
accessible only if the type is accessible and the member or
constructor is declared to permit access:
If the member or constructor is declared public, then access is
permitted. All members of interfaces are implicitly public.
Otherwise, if the member or constructor is declared protected, then
access is permitted only when one of the following is true:
Access to the member or constructor occurs from within the package
containing the class in which the protected member or constructor is
declared.
Access is correct as described in §6.6.2.
We jump to 6.6.2.2 and find:
A protected constructor can be accessed by a class instance creation expression (that does not declare an anonymous class) only from within the package in which it is defined.
access.test is in a different package and you declared the constructor protected. Only classes within access can call the constructor directly (e.g. using new - this is what "class instance creation expression" means).
Your data.Operations class extends access.test, which is fine since access.test was declared public. Your constructor is package-private, therefore you are allowed to call:
Operations o = new Operations("Operations!");
in data.Operations.main(). Operation's constructor calls super(s) which it is allowed to do because it's a subclass (in fact, it has to since there's no nullary constructor in the superclass). Note that this is not the same thing as calling the constructor directly via new.
If you were to have this:
Operations(String s){
super(s);
access.test t = new access.test(s);
}
It would produce the same error when trying to use new; you can't do that.
A protected method has different access rules than a protected constructor.
You've declared test1() in access.test as protected.
Declaring a method protected means classes in the access package and subclasses (regardless of package) can call it. Therefore, the following is perfectly valid in data.Operations.main():
Operations o = new Operations("Operations!");
o.test1("hi!");
If your main() was in a different class in your data package (or in another package and Operations had a public constructor), you couldn't do that.
package data;
public class ThirdClass {
public static void main(String[] args) {
// This is perfectly fine since Operations has a package-private constructor
Operations o = new Operations("Some String");
// This won't compile
o.test1("hi!");
}
}
Constructors are not inherited.
use it
public test(String s){
this.s = s;
System.out.println("access.test constructor");
}
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.
Related
Possible Duplicate
The top answer given there states that the protected constructor can be called using super() but cannot be instantiated using new? Why so? And if that is the reason then what is the difference between package-private(no modifier) and protected constructor?
The following code is not getting me any difference.
package pack1;
public class Rr {
protected Rr() {
System.out.println("Rello");
}
}
package pack2;
class Tt extends pack1.Rr {
Tt() {
super(); //works
pack1.Rr r = new pack1.Rr(); //error
}
}
class Uu {
public static void main(String args[]) {
Tt t = new Tt();
}
}
A protected method can be accessed via its sub-class objects.
Note, "sub-class" here is very important, which means "via a sub-class way", not "anywhere within a sub-class".
Let's look at an example.
Following are 2 classes:
package one;
public class A {
protected A() {} // protected constructor
public A(int i) {} // public constructor
protected void foo() {} // protected method
}
package two;
import one.A;
public class B extends A {
public void bar() {
this.foo(); // correct
A a = new A(0); // call A's public constructor to construct an A instance.
a.foo(); // compiler error: the method foo from the type A is not visible.
}
}
The first invocation is permitted, but the second not, why?
Like I said, the first one is accessing via "a sub-class way", in which this is A's sub-class instance; however the second just "within a sub-class" (here B is no meaning to A, it's just an ordinary class, so it can not access A's protected method).
Another example is Object.clone. This is a protected method of root class Object. You might likely say it can be accessed from any object created from any class, but the answer is capital "NO": only those codes which are using "sub-classes way" can access it.
The following illustrates this:
this.clone(); // ok
Object o = new Object();
o.clone(); // compiler error: the method clone from the type Object is not visible.
A "default constructor" is a constructor that Java generates if you don't provide one yourself; it's always has the same access as the class itself and has no arguments. Ie when you define
class YourClass {}
the system makes it
class YourClass {
YourClass() {} // default constructor
}
If you create a any other constructor - even a public one with no arguments - it is not a default constructor. The second code piece above would prevent the system from generating one, because you already declared it.
The same is true if you create a protected constructor. Compare:
public class Class1 {}
public class Class2 {
protected Class2() {}
}
you can instantiate Class1, but not Class2:
// invokes autogenerated default constructor
Class1 c1 = new Class1();
// compile error: default constructor is not generated because you declared a protected one
Class2 c2 = new Class2();
As #Turing85 states in a comment, the protected modifier only means that the declared constructor can only be invoked within the proper access scope - from subclasses or classes in the same package.
For completeness' sake: you can call both super() and the constructor explicitly from a subclass:
class Class3 extends Class2() {
public Class3() {
// call to protected constructor of Class2
super();
// explicit call to constructor by creating new instance
Class2 o = new Class2();
}
}
EDIT: I just tried it out, and the last sample is only valid if the two classes are in the same package. I don't know and would like to know.
protected gives access to subclasses, in addition to the classes in the same package.
When you call the constructor directly, e.g. new A() you can think of it as calling a static method. There is no instance of the class yet, thus inheritance rules cannot apply. Therefore, static access rules apply: if the constructor is protected, then it must be in the same package in order to be accessible.
Once you are inside a constructor code and you call super(), then you already have an instance, so if you are in a subclass and call the protected constructor it will work.
I try to understand why there is a difference between accessibility of class members when speaking about constructors.
Consider the following example:
class A {
static class B {
private B(String s) {}
private void foo() {}
}
static class C extends B {
public C(String s) {
super(s); // call B(String), which is private, and obviously accessible
}
void bar() {
foo(); // compilation error (symbol unknown), as B.foo() is private
}
}
}
Private members of A, as being private, should not be accessible from B. For fields and methods, it is the case, but it seems that constructors are not following the same rule.
From the JLS-8 (6.6.1. Determining Accessibility), we can read:
[...]
A member (class, interface, field, or method) of a reference type, or a constructor of a class type, is accessible only if the type is accessible and the member or constructor is declared to permit access:
[...]
Otherwise, the member or constructor is declared private, and access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
Can anyone explain me why the constructor is accessible from C, even while being declared private?
The method foo() is private, so you don't inherit it and can't call it directly from the C class.
However, you can see private methods and constructor from B since everything is declared in the same containing class, and access them with super, which is why super() works.
In the same way, you can access foo with super.foo().
Note that you can redefine a new foo method in C, but this method will not override B.foo().
So the trick here might be the following :
you cannot access foo because it is declared private so you don't inherit it in C.
However, as was noted in comments you can access super.foo(); because super refers to a type that is declared in the same top level class (see JLS 6.6.1 for this).
Then the trick is that calling super(s) can be viewed as calling super.<init>(s) which ends up being the same case as super.foo()
Foo() method is not accessible in class C, as foo() method is private and private method can not be inherited to base class.
For constructors, CONSTRUCTORS NEVER EVER BE INHERITED. Also, I compiled this code :
class Vehicle{
int speed=50;
private Vehicle()
{
System.out.println("Private Vehicle constructor");
}
}
public class Bike4 extends Vehicle{
int speed=100;
Bike4()
{
super();
System.out.println("Hi I n constructor");
}
void display(){
System.out.println(super.speed);//will print speed of Vehicle now
}
public static void main(String args[]){
Bike4 b=new Bike4();
b.display();
}
}
And get Compile time Error : Vehicle() has private access in Vehicle
super();
^
Which clearly indicates that a private constructor cannot be accessed using super. If we are able to initialize or access a private constructor, then what's the point in creating a private constructor.
In the book Java: The complete reference
// Demonstrate when constructors are called.
// Create a super class.
class A {
A() {
System.out.println("Inside A's constructor.");
}
}
// Create a subclass by extending class A.
class B extends A {
B() {
System.out.println("Inside B's constructor.");
}
}
// Create another subclass by extending B.
class C extends B {
C() {
System.out.println("Inside C's constructor.");
}
}
class CallingCons {
public static void main(String args[]) {
C c = new C();
}
}
Output:
Inside A’s constructor
Inside B’s constructor
Inside C’s constructor
It is demonstrating how the constructor of a subclass is called. But why are constructors of the super class called in the absence of a super() constructor.
Why did the Java Language designers consider it necessary to do so?
As others have pointed out, if you don't start your constructor with a super(...) call, the compiler will put in a call to super() for you.
As to the why, you have to start with remembering what a constructor is for in the first place: initializing the object. What does that mean, specifically? In practice, it means assigning values to the object's fields, and establishing invariants.
Without a call to super(), the B and A classes wouldn't have a chance to do that for whatever fields they contain. And you can't even have the C() constructor do it for them, if those fields are private, since private fields aren't accessible outside your class (not even your super class's fields are accessible). Even if you could, it wouldn't be a good idea; it would also break encapsulation. For instance, imagine having to change your code if a super class -- possibly a complex one whose internals you're not an expert in -- suddenly decided to change its implementation details.
To illustrate this, consider a very simple set of classes:
public class Super {
private final String name;
Super() {
name = "default";
}
public String name() {
return name.toUpperCase();
}
}
public class Sub extends Super {
public Sub() {
// don't do anything
}
}
When you instantiate Sub, it will start out by calling Super's constructor. If it didn't, the name field would be null (the default value for reference types). But the name() method doesn't check for null; it assumes that the reference is non-null, because the constructor establishes that invariant. So, in our pseudo-Java that doesn't call the super constructor, Super.name has to get a bit more complicated -- it has to check for name == null.
You can imagine that as the classes gain more fields, with more interesting invariants, this toy example can become more and more complicated. Forcing you to call the super constructor -- either explicitly or implicitly -- lets the authors of that super class establish their invariants, resulting in simpler, more maintainable code.
Every constructor calls its superclass constructor. super() call take place as the first line in the constructor. From javadoc:
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the
no-argument constructor of the superclass. If the super class does not
have a no-argument constructor, you will get a compile-time error.
Object does have such a constructor, so if Object is the only
superclass, there is no problem.
more here
Because it says so in the Java Language Specification.
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments.
Even it has a role with Abstract classes also. we can't initialize object of abstract class. But Child class of Abstract class calls the super() method by default. So abstract class constructor can initialize its instance variables.
for example:
public abstract class TestA {
private int a;
public TestA()
{
a=10;
}
public int displayA()
{
return a;
}
abstract void display();
}
public class TestB extends TestA{
#Override
void display() {
System.out.println("this is class B");
}
}
package Abstract;
public class TestMain {
public static void main(String[] args) {
TestA obj= new TestB();
System.out.println(obj.displayA());
}
}
Output is : 10
Here you can see, when we initiating object of class TestB , by default super constructor is calling and TestA's constructor is assigning the value of a. If super will not be called by default we can't assign instance variables of abstract class.
Inheritance is basically inheriting all the properties of your parent class. So if a sub class constructor is called, it should definitely and by default inherit all its parent class properties also. In the following code, all the properties of class A should be made available in class B also, so if I just call B's constructor, all the class A's properties(except private) are also initialized and made available, meaning B has inherited A's properties
class A {
protected int a;
A() {
a=12;
System.out.println("Inside A's constructor.");
}
}
class B extends A {
B() {
System.out.println("Inside B's constructor.");
System.out.println(a);
}
}
public class ConstructorInheritance {
public static void main(String args[]) {
B b=new B();
}
}
output:
Inside A's constructor.
Inside B's constructor.
12
Imagine class C accessing an unitialized variable of class B or A. Implicitly calling constructors of class B-->class A makes sure that you are always accessing initialized variables of inherited classes(A or B)
"The Java programming language" says "A constructor in subclass can initialize its individual state, however, as keeping contract, only super class knows how to initialize super class's state".
Thus, constructor of super class have to be called. There is sequence how the constructor processed:
Call super class constructor
Initialize fields with initializers and initialization blocks
Execute body of the constructor
For more details, have a look of the book to section "3.2".
I would like to understand what's happening in the example below (where a protected member is being accessed from outside the package through a subclass).
I know for classes outside the package, the subclass can see the protected member only through inheritance.
There are two packages: package1 and package2.
package1: ProtectedClass.java
package org.test.package1;
public class ProtectedClass {
protected void foo () {
System.out.println("foo");
}
}
package2: ExtendsprotectedClass.java
package org.test.package2;
import org.test.package1.ProtectedClass;
public class ExtendsprotectedClass extends ProtectedClass {
public void boo() {
foo(); // This works,
// since protected method is visible through inheritance
}
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // Why is this working?
// Since it is accessed through a reference,
// foo() should not be visible, right?
}
}
package2: UsesExtendedClass.java
package org.test.package2;
public class UsesExtendedClass {
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // CompilationError:
// The method foo() from the type ProtectedClass
// is not visible
}
}
It is understood that the boo() method in ExtendsprotectedClass can access foo(), since protected members can be accessed through inheritance only.
My question is, why is the foo() method working fine when accessed through a reference in the main() method of ExtendsprotectedClass but will not work when accessed through the epc reference in UsesExtendedClass?
Code within the ExtendsprotectedClass class is allowed to access protected members of ProtectedClass via a reference of type ExtendsprotectedClass. From the JLS section 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.
and
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. [...]
UsesExtendedClass isn't reponsible for the implementation of ExtendsprotectedClass, hence the final call fails.
EDIT: The reasoning behind this is that protected access is designed to help subclasses implement the functionality they need, giving more access to the internals of the superclass than would normally be available. If that were available to all code, it would be pretty close to making the method public. Basically, the subclasses are trusted not to break encapsulation; they're given more capabilities within objects of their own type. The public API shouldn't expose those details, but the protected API can just for the purposes of giving subclasses more opportunities.
It is working in the first case because it is being called from the same class even the method is being accessed through a reference. You could even call a private method of ExtendsprotectedClass through a reference in the same main method.
I believe you've answered your own question; UsesExtendedClass does not inherit from ProtectedClass, and -- by definition -- "protected" members are accessible only in the class in which they are declared / defined or in a class that inherits from the one in which they are declared or defined.
take a look on this picture from : http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
its clear that protected member of class can be accessed via subclass.
I would like to understand what's happening in the example below (where a protected member is being accessed from outside the package through a subclass).
I know for classes outside the package, the subclass can see the protected member only through inheritance.
There are two packages: package1 and package2.
package1: ProtectedClass.java
package org.test.package1;
public class ProtectedClass {
protected void foo () {
System.out.println("foo");
}
}
package2: ExtendsprotectedClass.java
package org.test.package2;
import org.test.package1.ProtectedClass;
public class ExtendsprotectedClass extends ProtectedClass {
public void boo() {
foo(); // This works,
// since protected method is visible through inheritance
}
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // Why is this working?
// Since it is accessed through a reference,
// foo() should not be visible, right?
}
}
package2: UsesExtendedClass.java
package org.test.package2;
public class UsesExtendedClass {
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // CompilationError:
// The method foo() from the type ProtectedClass
// is not visible
}
}
It is understood that the boo() method in ExtendsprotectedClass can access foo(), since protected members can be accessed through inheritance only.
My question is, why is the foo() method working fine when accessed through a reference in the main() method of ExtendsprotectedClass but will not work when accessed through the epc reference in UsesExtendedClass?
Code within the ExtendsprotectedClass class is allowed to access protected members of ProtectedClass via a reference of type ExtendsprotectedClass. From the JLS section 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.
and
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. [...]
UsesExtendedClass isn't reponsible for the implementation of ExtendsprotectedClass, hence the final call fails.
EDIT: The reasoning behind this is that protected access is designed to help subclasses implement the functionality they need, giving more access to the internals of the superclass than would normally be available. If that were available to all code, it would be pretty close to making the method public. Basically, the subclasses are trusted not to break encapsulation; they're given more capabilities within objects of their own type. The public API shouldn't expose those details, but the protected API can just for the purposes of giving subclasses more opportunities.
It is working in the first case because it is being called from the same class even the method is being accessed through a reference. You could even call a private method of ExtendsprotectedClass through a reference in the same main method.
I believe you've answered your own question; UsesExtendedClass does not inherit from ProtectedClass, and -- by definition -- "protected" members are accessible only in the class in which they are declared / defined or in a class that inherits from the one in which they are declared or defined.
take a look on this picture from : http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
its clear that protected member of class can be accessed via subclass.