Subclassing a class with a private default constructor in Java - java

Say I have class A with a private constructor, and class B that extends it:
public class A {
private A() {}
}
public class B extends A {
public B(){
// error - there is no default constructor available in 'A'
}
}
I know it is possible to call private constructors via Java Reflection, but how can I do it in the B constructor? Thanks.

If class B extends A and A's constructor is private, subclassing is not possible unless both classes are defined in the same file as inner classes (see Preventing Instantiation of a Class). That's because the constructor of the subclass does an (either explicit or implicit) super() call. A super() call is basically just a call to the matching constructor and if that constructor is declared private, this call is not possible from some outer class (e.g. one defined in a different file).

Related

What does "extends" actually do?

I am currently studying the concept of "class abstraction" and "extension" and have been wondering:
"If I declare a parametrized constructor inside my abstract class why won't extension on another class work unless I declare myself the constructor with the super keyword invoking the parameters of the abstract class's constructor?"
I understand the fact that extension instances the previous abstract class into the extended one and tries to call the default constructor but have been wondering why it gives out an error.
Is it because the constructor has been parametrized or simply because the empty constructor does not exist?
Does the extends keyword call something along the lines of this?
Object myClass = new AbstractClass();
And the missing parameters are the reason why it gives out an error so something along the lines of this would be correct
Object myClass = new AbstractClass(int foo,float boo);
And if that is it, does the super keyword essentially, if you'll allow me the term, "put" the parameters given in the parenthesis "inside" the constructor?
If that's not it what am I getting wrong? How does it actually work?
You should think of the extends keyword, in this context, as just saying that a class is the subclass of another class, and does nothing else. And that there are rules governing how subclasses and superclasses should work.
When you construct a subclass, you must construct its superclass first. For example, to create a Bird, you must first create an Animal. That makes sense doesn't it? To demonstrate this in code:
class Animal {
public Animal() {
System.out.println("Animal");
}
}
class Bird extends Animal {
public Bird() {
System.out.println("Bird");
}
}
Doing new Bird() will first print Animal and then Bird, because the Animal's constructor is called first, and then the Bird constructor. So actually, the Bird constructor implicitly calls the superclass' constructor. This can be written as:
public Bird() {
super();
System.out.println("Bird");
}
Now what happens if the super class does not have a parameterless constructor? Let's say the constructor of Animal now takes a String name as argument. You still need to call the superclass' constructor first, but super() won't work because super() needs a string parameter!
Therefore, the compiler gives you an error. This can be fixed by calling super() explicit with a parameter.
"If I declare a parametrized constructor inside my abstract class why
won't extension on another class work unless I declare myself the
constructor with the super keyword invoking the parameters of the
abstract class's constructor?"
Because the super class says that it MUST be constructor using that declared constructor and there is no other way around. This applies to every extending class - required constructor must be called.
The same happens with any class when you declare other constructor than default one. For example, having
public class A{
//no default no-arg ctor here
public A(String name){
....
}
}
public class B{
//default no-arg ctor will be created
}
so then
B b=new B();
A a=new A(); //// INVALID!
A a=new A("foobar"); // yeah that is it
The same applies when you are extending classes. To construct child instance, you must first "internally create parent instance" calling super.constructor. Since there is no default constructor, ANY of explicit declared superconstructors must be used.
When initializing an Object the constructor will always be called. Even if you do not define one constructor there will be a default one without any parameters. So if you define a constructor in the abstract class, you have to call that constructor with super().
If you do not define any constructors, then it will be implicitly called as the default one.
If I declare a parametrized constructor inside my abstract class why won't extension on another class work unless I declare myself the constructor with the super keyword invoking the parameters of the abstract class's constructor?
There is no default constructor available in AbstractClass since you define a parametrised constructor. If you don't define a constructor yourself, a default constructor without arguments is implicitly created. You can manually add such one now or you need to use the only available constructor (which is parametrised) with super().
Example of your code with defining constructor without arguments:
class AbstractClass {
AbstractClass() {} // added manually since not created implicitly
AbstractClass(int foo, float boo) {}
}
class RealClass extends AbstractClass {
RealClass() { } // calls super() implicitly
}
AbstractClass myClass = new RealClass();
Example of your code with calling super() with arguments:
class RealClass extends AbstractClass {
RealClass() {
super(1, 2);
}
}
class AbstractClass {
AbstractClass(int foo, float boo) {}
}
AbstractClass myClass = new RealClass();

Why does a private base class constructor result in "Implicit super constructor is not visible"

If constructors do not inherits in Java, why do I get compile error(Implicit super constructor A() is not visible for default constructor. Must define an explicit constructor)?
class A {
private A() {
}
}
public class B extends A {
}
UPD. I know that super() is called in implicit B constructor. But i don't get why it can't access private constructor with super(). So, if we have only private constructors, class de facto is final?
if B extends A, B must have an access to an A constructor.
Keep in mind that a constructor always call super().
So here, the implicit parameterless constructor of B can't call the A constructor.
In Java, if you create an instance of Child Class, Parent Class instance gets created implicitly.
So Child Class constructor should be visible to Child Class as it calls the constructor of Parent Class constructor using super() in the first statement itself.
So if you change the constructor of the Parent Class to private, Child Class could not access it and could not create any instance of its own, so compiler on the first hand just does not allow this at all.
But if you want to private default constructor in Parent Class, then you need to explicitly create an overloaded public constructor in the Parent Class & then in Child class constructor you need to call using super(param) the public overloaded constructor of Parent Class .
Moreover, you might think then what's the use of private constructors. private constructors is mostly used when you don't want others from any external class to call new() on your class. So in that case, we provide some getter() method to provide out class's object.In that method you can create/use existing Object of your class & return it from that method.
Eg. Calendar cal = Calendar.getInstance();. This actually forms the basis of Singleton design pattern.
The important point is to understand that the first line of any constructor is to call the super constructor. The compiler makes your code shorter by inserting super() under the covers, if you do not invoke a super constructor yourself.
Now if you make that constructor in superclass private, above mentioned concept will fail.
Your class B has a default constructor, B() - because you didn't explicitly define any other one.
That constructor implicitly calls its super constructor, A().
But you have explicitly made that one private to class A, so you have explicitly declared that no other class, including B, can have access to it.
Can work
class A {
private A() {
}
public A(int i){
}
}
public class B extends A {
private A(){
super(10);
}
}
Or remove the private A(), defaults to public A(),
unless you have another constructor
class A {
}
public class B extends A {
private A(){
super();
}
}
An instance of class B creates an instance of class A so B must invoke super(...) if A implements a non default constractor. So the constructor should be protected for B being able to call super(...)
public class B extends A {
/*
* The default constructor B means
* public () B {super();}
*/
public B() {
}
}
So you should define a constructor which is accessible by the class B
You can change the access modifier for parent Constructor
Or else you can define other Constructor in parent class which is accessible by class B and call that constructor.

Anonymous initialization of class with protected constructor

Let's assume we have a class:
public class SomeClass {
protected SomeClass () {
}
}
In MainClass located in different package I tried to execute two lines:
public static void main(String[] args) {
SomeClass sac1 = new SomeClass();
SomeClass sac2 = new SomeClass() {};
}
Because of protected constructor, in both cases I was expecting program to fail. To my suprise, anonymous initialization worked fine. Could somebody explain me why second method of initialization is ok?
Your anonymous class
SomeClass sac2 = new SomeClass() {};
basically becomes
public class Anonymous extends SomeClass {
Anonymous () {
super();
}
}
The constructor has no access modifier, so you can invoke it without problem from within the same package. You can also invoke super() because the protected parent constructor is accessible from a subclass constructor.
Those two little braces in
SomeClass sac2 = new SomeClass() {};
invoke a lot of automatic behavior in Java. Here's what happens when that line is executed:
An anonymous subclass of SomeClass is created.
That anonymous subclass is given a default no-argument constructor, just like any other Java class that is declared without a no-argument constructor.
The default no-argument constructor is defined with visibility public
The default no-argument constructor is defined to call super() (which is what no-arg constructors always do first).
The new command calls the no-argument constructor of this anonymous subclass and assigns the result to sac2.
The default no-argument constructor in the anonymous subclass of SomeClass has access to the protected constructor of SomeClass because the anonymous subclass is a descendant of SomeClass, so the call to super() is valid. The new statement calls this default no-argument constructor, which has public visibility.
The first line fails, because SomeClass's constructor is protected and MainClass is not in SomeClass's package, and it isn't subclassing MainClass.
The second line succeeds because it is creating an anonymous subclass of SomeClass. This anonymous inner class subclasses SomeClass, so it has access to SomeClass's protected constructor. The default constructor for this anonymous inner class implicitly calls this superclass constructor.
Your line
SomeClass sac2 = new SomeClass() {};
creates an instance of a new class which extends SomeClass. Since SomeClass defines a protected constructor without arguments, a child class may call this implicitly in its own constructor which is happening in this line.

Java compiler super() constructor generals [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Use of ‘super’ keyword when accessing non-overridden superclass methods
I'm new to Java and have been reading a lot about it lately to get more knowledge and experience about the language. I have a question about inherited methods and extending classes when the compiler inserts automatic code.
I've been reading that if I create class A with some methods including lets say a method called checkDuePeriod(), and then create a class B which extends class A and its methods.
If I then call the method checkDuePeriod() within class B without using the super.checkDuePeriod() syntax, during compilation will the compiler include the super. before checkDuePeriod() or will the fact that the compiler includes the super() constructor automatically when compiling the class imply the super. call of the methods that class B calls from class A?
I'm a little confused about this. Thanks in advance.
The super class's implementation of regular methods is not automatically invoked in sub classes, but a form of the super class's constructor must be called in a sub class's constructor.
In some cases, the call to super() is implied, such as when the super class has a default (no-parameter) constructor. However, if no default constructor exists in the super class, the sub class's constructors must invoke a super class constructor directly or indirectly.
Default constructor example:
public class A {
public A() {
// default constructor for A
}
}
public class B extends A {
public B() {
super(); // this call is unnecessary; the compiler will add it implicitly
}
}
Super class without default constructor:
public class A {
public A(int i) {
// only constructor present has a single int parameter
}
}
public class B extends A {
public B() {
// will not compile without direct call to super(int)!
super(100);
}
}
If you call checkDuePeriod() in B without super., means you want to invoke the method that belongs to the this instance (represented by this within B) of B. So, it equivalent to saying this.checkDuePeriod(), so it just doesn't make sense for the compiler to add super. in the front.
super. is something that you must explicitly add to tell the compiler that you want to call the A's version of the method (it is required specially in case B has overridden the implementation provided by A for the method).
Call of super() as a default constructor (constructor with no args) can be direct or non direct but it garants that fields of extendable class are properly initialized.
for example:
public class A {
StringBuilder sb;
public A() {
sb = new StringBuilder();
}
}
public class B extends A {
public B() {
//the default constructor is called automatically
}
public void someMethod(){
//sb was not initialized in B class,
//but we can use it, because java garants that it was initialized
//and has non null value
sb.toString();
}
}
But in case of methods:
Methods implement some logic. And if we need to rewrite logic of super class we use
public class B extends A {
public B() {
}
public boolean checkDuePeriod(){
//new check goes here
}
}
and if we want just implement some extra check, using the value returned from checkDuePeriod() of superclass we should do something like this
public class B extends A {
public B() {
}
public boolean checkDuePeriod(){
if(super.checkDuePeriod()){
//extra check goes here
}else{
//do something else if need
}
return checkResult;
}
}
First about the Constructors:
- When ever an object of a class is created, its constructor is initialized and at that time immediately the constructor of its super-class is called till the Object class,
- In this process all the instance variables are declared and initialized.
- Consider this scenario.
Dog is a sub-class of Canine and Canine is a sub-class of Animal
Now when Dog object is initialized, before the object actually forms, the Canine class object must be form, and before Canine object can form the Animal class object is to be formed, and before that Object class object must be form,
So the sequence of object formed is:
Object ---> Animal ---> Canine ---> Dog
So the Constructor of the Super-Class is Called before the Sub-Class.
Now with the Method:
The most specific version of the method that class is called.
Eg:
public class A{
public void go(){
}
}
class B extends A{
public static void main(String[] args){
new B().go(); // As B has not overridden the go() method of its super class,
// so the super-class implementation of the go() will be working here
}
}

Why does a Java constructor have to be public or protected for a class to be extended outside its package?

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.

Categories

Resources