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.
Related
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).
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();
I'm reading java docs and reading about Constructors I got confused about the below paragraph.
You don't have to provide any constructors for your class, but you
must be careful when doing this. The compiler automatically provides a
no-argument, default constructor for any class without constructors.
This default constructor will call the no-argument constructor of the
superclass. In this situation, the compiler will complain if the
superclass doesn't have a no-argument constructor so you must verify
that it does. If your class has no explicit superclass, then it has an
implicit superclass of Object, which does have a no-argument
constructor.
What does mean that the compiler will complain if the superclass doesn't have a no-argument constructor
Reference: Java Docs
https://docs.oracle.com/javase/tutorial/java/javaOO/constructors.html
Let's imagine a Base class such as
public class Base {
public Base(String s) {
}
}
Let's now create a subclass:
public class Sub extends Base {
}
That won't compile, because the above code is equivalent to
public class Sub extends Base {
// added by compiler because there is no explicitely defined constructor in Sub
public Sub() {
}
}
which is equivalent to
public class Sub extends Base {
// added by compiler because there is no explicitely defined constructor in Sub
public Sub() {
// added by compiler if there is no explicit call to super()
super();
}
}
The line super()tries to call the no-arg constructor of Base, but there is no such constructor.
The only way to have Sub compile is thus to explicitely define a constructor such as
public class Sub extends Base {
public Sub() {
super("some string");
}
}
By default every class has a no-argument constructor. If you create class A with a constructor with arguments, when class B extends A, you need to explicitly create a constructor which will call the super class constructor with arguments. Basically when you create a constructor, you lose the default call to the no-arg constructor (unless the constructor you created is still a no-arg constructor.
A constructor of the superclass and the subclass has to be called, implicitly or explicitly. Always.
If you provide a constructor for the subclass yourself, you can choose, which superclass constructor to call.
But if you don't provide a constructor for your subclass, Java creates a no-argument constructor for you. In that constructor it has to call a superclass constructor. But if there is no no-argument constructor in the superclass, Java cannot know which superclass constructor to call and which argument to use to do so.
class Superclass {
Superclass(String argument) {
//...
}
}
class Subclass extends Superclass {
// Implicit no-argument constructor, created by Java
Subclass() {
super(/* what String can Java put here? it cannot know it */);
}
}
Now, if there is a no-argument constructor of Superclass, Java can just call super(); in the default Subclass constructor.
Btw. that also happens automatically, if you define the Subclass constructor yourself and don't add an explicit call to a Superclass constructor. The Subclass constructor always calls a Supeclass constructor, be it explicitly or implicitly.
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.
In Java, I can't create instances of abstract classes. So why doesn't eclipse scream about the following code?
public abstract class FooType {
private final int myvar;
public FooType() {
myvar = 1;
}
}
The code is fine, the final variable is initialized in the constructor of FooType.
You cannot instantiate FooType because of it being abstract. But if you create a non abstract subclass of FooType, the constructor will be called.
If you do not have an explicit call to super(...) in a constructor, the Java Compiler will add it automatically. Therefore it is ensured that a constructor of every class in the inheritance chain is called.
You can have constructors, methods, properties, everything in abstract classes that you can have in non-abstract classes as well. You just can't instantiate the class. So there is nothing wrong with this code.
In a deriving class you can call the constructor and set the final property:
public class Foo extends FooType
{
public Foo()
{
super(); // <-- Call constructor of FooType
}
}
if you don't specify a call to super(), it will be inserted anyway by the compiler.
You can create concrete sub-classes of FooType and they will all have a final field called myvar.
BTW: A public constructor in an abstract class is the same as a protected one as it can only be called from a sub-class.
What is your doubt?
Ok. See, an abstract class can have a constructor. It's always there-implicit or explicit. In fact when you create an object of a subclass of an abstract class, the first thing that the constructor of the subclass does is call the constructor of its abstract superclass by using super(). It is just understood, that's why you don't have to write super() explicitly unless you use parameterized constructors. Every class even if it is abstract, has an implicit constructor which you cannot see. It is called unless you create some constructor of your own. so long you created abstract classes without creating any custom constructor in it, so you didn't know about the existence of the implicit constructor.
You definitely can declare final variable in abstract class as long as you assign value to it either in the constructor or in declaration. The example that guy gave makes no sense.
No you can't declare final variables inside an Abstract class.
Check Below example.
public abstract class AbstractEx {
final int x=10;
public abstract void AbstractEx();
}
public class newClass extends AbstractEx{
public void AbstractEx(){
System.out.println("abc");
}
}
public class declareClass{
public static void main(String[] args) {
AbstractEx obj = new newClass ();
obj.AbstractEx();
// System.out.println(x);
}
}
This code runs correct and produce output as
abc
But if we remove comment symbol of
System.out.println(x);
it will produce error.