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.
Related
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".
In the following example:
class A {
private int a;
private int b;
private int c;
public A(int a, int b , int c) {
this.a = a;
this.b = b;
this.c = c;
}
}
class B extends A {
public B() {
super(1,2,3);
}
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
You cannot call super() like this:
class B extends A {
super(1,2,3);
}
super() OR this() should be the first statement in a constructor. First correct this basic mistake of yours before going further. super() is used by default even if you don't explicitly use it.
class B extends A {
B (){
super(1,2,3);
}
}
This is the right way. Please Read about Constructors and Java language basics first before posting questions.
EDIT
I didn't notice that someone edited you question to add super(1,2,3) in a constructor, now answering your questions as follows:
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
No, by calling super(1,2,3) all you're doing is passing 3 integer values to the base class constructor public A(int a, int b , int c) After that you're assigning these values to the private instance variables of base class, you're not making a separate fields for class B, if thats what you asked, and No B class still can't access base class instance variables directly (by stating directly I mean by inheritance or making an instance, there are other ways like setters/getters etc)
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
No, if you don't use a constructor in B class which uses super(int, int, int) to match the arguments of base class constructor (int a, int b , int c) then your code won't even compile. The default constructor will call the no-args constructor of Base class, but since Base class has no default constructor you'll get compilation error!
First of all, the code you posted is not valid Java. It is important that you post working code, otherwise we can't be sure about what you are asking.
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
Assuming you put the statement in a constructor instead of at class level, which is illegal, then no, that will not automatically create fields in class B. It just calls the constructor in the superclass A that takes three int arguments and initializes the fields in the superclass part of the object.
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
Since there is no default (i.e. no-arguments) constructor in class A, you would get a compiler error - the compiler would complain that there is no appropriate constructor in class A.
Java only automatically adds a no-arguments constructor to a class if you do not specify a constructor at all in the class. Since class A already has a constructor, Java is not automatically going to add a no-arguments constructor.
First of all you need to understand one thing: private fields of a parent class ARE BEING INHERITED. The only thing is that if they are private in parent, then they cannot be accessed directly from the child class (the B class in your example). So in other words: not a single B class method can access those fields, but every A class method can access them. So for example its possible that there is a public/protected method inside A class that changes some of those fields and this method can be called from a child class (B).
Once you correct your class to the proper:
class B extends A {
public B() {
super(1,2,3);
}
}
...we can proceed to answer your actual questions.
The constructor of A does not create fields. The fields are created as part of creating of any A object, and are initialized by the constructor.
Those fields are created in B as well, but not because you called super(1,2,3) but because you extend A. As soon as an instance of B, which is an extended instance of A is created, those fields are there - but they are accessible only to methods that are declared in A itself and not in its descendents.
By calling super(1,2,3), you are initializing those private fields. They are still not accessible to B. The constructor of A is mediating between B and these private variables. If you had a method that prints those fields in A, and that method was not private, you could call it and it would print them with these values.
As for your second question, if you didn't call the super(1,2,3), Java would try to call the default constructor. However, for a class that has a constructor, there is no default constructor. The empty/nullary constructor only exists if you either declared it yourself, or if you didn't declare any constructor at all.
// The following two classes have a default constructor which will be called
// if any descendent doesn't call super(...)
class HasADefaultConstructor {
}
class AlsoHasADefaultConstructor {
AlsoHasADefaultConstructor() {
}
}
// But this one doesn't.
class DoesntHaveADefaultConstructor {
DoesntHaveADefaultConstructor( String a ) {
}
}
So you can't inherit private varibles, but you can access them if the parent class has the appropriate getters:
Run the example and you see the output is 'a is: 1'
Regarding the default constructor: In your example you have explicitly implemented
a constructor. So the implicit default constructor is not there any more
class B extends A {
public B() {
super(1, 2, 3);
}
public void foo() {
System.out.println("a is: " + super.getA());
}
public static void main(String[] args) {
B bb = new B();
bb.foo();
}
}
class B extends A {
public B() {
super(1, 2, 3);
}
public void foo() {
//access a
System.out.println("a is: " + super.getA());
}
public static void main(String[] args) {
B bb = new B();
bb.foo();
}
}
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.
I have a class which defines all of the basic parameters for a given screen. From here every screen in the application is a subclass of this. I need every screen (i.e. subclass) to set the value of a variable in its implementation (namely, each screen must define what level it is in a navigation tree).
Also, ideally, this variable should be final when it is set in the sub classes (I realise this probably isn't possible).
What is the best way to go about this? Is there a way to correctly enforce this type of behaviour in Java?
#pst's comment lead to this solution.
This can't be done with a variable. But an abstract class can require that a particular method is implemented: this method could return the applicable value
From declaring an abstract function to set or return the variable, you can force any subclass to implement it correctly.
Next, the function must be called by every single subclass of the outer class. This implies that it must be done somewhere in the outer class. This can be done in the no-argument constructor of the outer class without having to worry about subclasses calling super:
Note: 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.
(Java docs: Super)
Based on that, this solution will hold up and correctly force the variable to be set as long as either:
No other constructor is created in the superclass (hence super can't be used in a subclass to call a different constructor instead)
All other constructors in the superclass still call the default constructor internally
The code:
Superclass:
public abstract class SuperClass {
// Variable all inner classes must set
static int myVar = 0;
public SuperClass() {
myVar = giveValue();
}
public abstract int giveValue();
}
Subclass:
public class SubClass extends SuperClass {
#Override
public int giveValue() {
return 5; // individual value for the subclass
}
}
Rather than enforce that child class instances initialize the fields, you could follow a strategy of composition by having your parent class constructor take a parameter implementing an interface that provides the fields you wish to have initialized.
class Screen {
final Configuration config;
Screen(Configuration config) {
this.config = config;
}
// or
Screen(ConfigFactory configFactory) {
this.config = configFactory.make();
}
}
interface ConfigFactory {
Configuration make();
}
I would caution against requiring a subclass instance initializing the configuration, say using an abstract method implementation. The assignment in the parent class constructor occurs before the subclass instance is initialized, implicitly making proper computation of the configuration static.
If the computation isn't static, you risk null references or NullPointerExceptions by developers following you (or yourself if your memory is less than perfect). Make it easier on your collaborators (and yourself) and make the constraints explicit.
As mentioned by #Ketan in #B T's answer, invoking an overridable method from constructor is not especially a good practice (https://help.semmle.com/wiki/display/JAVA/Non-final+method+invocation+in+constructor)
One way to avoid this problem consists in having an abstract (protected) getter for the field. Hence the superclass doesn't have the field anymore, but it is still accessible in the super class using the getter. Each subclass is forced to declare the field because it must override the abstract getter.
Superclass:
public abstract class SuperClass {
public SuperClass() {}
protected abstract int getMyVar();
public void functionUsingMyVar(){
int a = 12 + getMyVar();
}
}
Subclass1:
public class SubClass1 extends SuperClass {
private int myVar;
public SubClass1() {
super();
myVar = 1;
}
#Override
protected int getMyVar(){
return myVar;
}
}
Subclass2:
public class SubClass2 extends SuperClass {
private int myVar;
public SubClass2() {
super();
myVar = 1;
}
#Override
protected int getMyVar(){
return myVar;
}
}
instead of having for the superclass (where giveValue() is overridable and called in the constructor) :
public abstract class SuperClass {
private int myVar;
public SuperClass() {
myVar = giveValue();
}
protected abstract int giveValue();
public void functionUsingMyVar(){
int a = 12 + myVar;
}
}
I tried with below example, it is working fine.
I expected it to pick sub-class's value since object won't be created for super class (as it is abstract). But it is picking up super class's field value only.
Please help me understand what is the concepts behind this?
abstract class SuperAbstract {
private int a = 2;
public void funA() {
System.out.println("In SuperAbstract: this.a " + a);
}
}
class SubClass extends SuperAbstract {
private int a = 34;
}
I am calling new SubClass.funA();
I am expecting it to print 34, but it is printing 2.
P.S.:
What I want to know is why using this in an abstract class not giving me an error?
As below text is emphasizing this would work on an instance and abstract classes won't have an instance.
Within an instance method or a
constructor, this is a reference to
the current object — the object whose
method or constructor is being called.
You can refer to any member of the
current object from within an instance
method or a constructor by using this.
from: http://java.sun.com/docs/books/tutorial/java/javaOO/thiskey.html
To answer the question in the title: Yes, this can be used in an abstract class. An abstract Animal is created at the same time as a Dog is created.
Overriding fields
You can't override fields the way you have tried it. Fields "are not virtual" like methods.
From Java Quick Reference: Overloading, Overriding, Runtime Types and Object Orientation - Overriding Methods
fields cannot be overridden but they can be hidden ie if you declare a field in a subclass with the same name as one in the superclass, the superclass field can only be accessed using super or the superclasses type
If you could, the field would probably have had to be at least protected :-)
Creation of objects of abstract classes
since object won't be created for super class (as it is abstract)
It is actually instantiated.
The abstract keyword only ensures that, when instantiated, it's instantiated in the form of a subclass. When instantiating a Dog, you're at the same time instantiating an Animal! The this reference in the context of an Animal will thus always refer to a Dog or a Cat or whatever, but in all cases it refers to some Animal. :-)
As the example below illustrates, the this reference makes sense even in an abstract class:
abstract class Animal {
public String name;
public Animal(String name) {
System.out.println("Constructing an Animal");
this.name = name;
}
public abstract void speak();
}
class Dog extends Animal {
public Dog(String name) {
super(name);
System.out.println(" Constructing a Dog");
}
public void speak() {
System.out.println("Bark! My name is " + name);
}
}
public class Test {
public static void main(String... args) {
new Dog("Woffy").speak();
}
}
Prints:
Constructing an Animal
Constructing a Dog
Bark! My name is Woffy
Update: The this reference refers to the same object in the super class as in the sub class.
You could try to add
public Animal getSuperThis() { return this; }
to the animal class, and do
System.out.println(this == getSuperThis());
in Dog.speak(). You would see that it prints true.
Any field declared in a class is unique, even if it has the same name as a a field in a base class (i.e. only methods can be overridden, but not fields). Therefore, there are two distinct fields in the derived class: SuperAbstract.a and SubClass.a. The fact that the base class is abstract has no impact.
The abstract keyword simply signifies that a class cannot be instantiated, i.e. you cannot write new SuperAbstract(). You can only instantiate object of the subclass, which must override all methods marked abstract.
The code you provided contains variable a as private member of the SuperAbstract class. Since, you don't seem to override the function, it represents the code from the SuperAbstract class, and executing it will get access to the a declared in the class itself, regardless of the fact that it is being called from any inherited class. To access the value of the later variable, you need to override the function by defining the function again in the derived class. The final code looks like this:
abstract class SuperAbstract {
protected int a = 2;
public void funA() {
System.out.println("In SuperAbstract:" + this.a);
}
}
class SubClass extends SuperAbstract {
private int a = 34;
//Overriding the above function
public void funA() {
System.out.println("In SubClass: " + a);
//Or even check using the super keyword
System.out.println("In SubClass with super: " + super.a);
//Now call the function to display the value of a from SuperAbstract
super.funA();
}
}
In the above code I changed the a to protected, so that it could be accessed from the derived class too.