I'm learning about inheritance and am working with this simple program that has has a superclass and a subclass as shown below. My question isn't specific to this program; however, this is where I've first seen this happen so I'm using it as an example for a more general conceptual question. Why does simply instantiating the class run the constructors and output the contents? My previous understanding was that instantiating the class simply creates the object but it wont do anything.
SuperClass1.java
public class SuperClass1 {
public SuperClass1(){
System.out.println("This is the superclass constructor.");
}
}
SubClass2.java
public class SubClass2 extends SuperClass1
{
public SubClass2()
{
System.out.println("This is the subclass constructor.");
}
}
Main.java
public class Main {
public static void main(String[] args)
{
SubClass2 obj1 = new SubClass2(); // why should this print something?
}
}
Output
This is the superclass constructor.
This is the subclass constructor.
First of all, instantiating an object means calling (and executing) the constructor, that is what it is for.
So, this:
SubClass2 newInstance = <createNewInstance>;
newInstance.<init()>;
is both done by the constructor call new SubClass2() in Java. There is no separation between "constructing" the object and "initialising" its properties.
Furthermore, if you do not explicitly call another constructor of a super class the default constructor (the one without arguments) is automatically called first thing when creating an object of a class. So instantiating an object of the subclass calls the superclass contructor (which prints the first line), and then prints the second line itself.
More in detail, the subclass looks like this behind the scene:
public class SubClass2 extends SuperClass1
{
public SubClass2()
{
super(); // calls the superclass constructor
System.out.println("This is the subclass constructor.");
}
}
Because the constructor you call includes a print statement.
You call the constructor method SubClass2() which has a print statement in it.
The statements are not printed because the class ist loaded, but because an object of that class in instantiated and the constructors are called:
That a class can be loaded without using constructor is demonstrated by the following code:
public class Test {
public static void main(String[] args) {
try {
Class.forName("Test$Inner");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
static class Inner {
static {
System.out.println("static initializer");
}
public Inner() {
System.out.println("inner ctor");
}
}
}
running that program shows that only the static class initializer is called and no constructor.
Related
I wrote this simple class in java just for testing some of its features.
public class class1 {
public static Integer value=0;
public class1() {
da();
}
public int da() {
class1.value=class1.value+1;
return 5;
}
public static void main(String[] args) {
class1 h = new class1();
class1 h2 = new class1();
System.out.println(class1.value);
}
}
The output is:
2
But in this code:
public class class1 {
public static Integer value=0;
public void class1() {
da();
}
public int da() {
class1.value=class1.value+1;
return 5;
}
public static void main(String[] args) {
class1 h = new class1();
class1 h2 = new class1();
System.out.println(class1.value);
}
}
The output of this code is:
0
So why doesn't, when I use void in the constructor method declaration, the static field of the class doesn't change any more?
In Java, the constructor is not a method. It only has the name of the class and a specific visibility. If it declares that returns something, then it is not a constructor, not even if it declares that returns a void. Note the difference here:
public class SomeClass {
public SomeClass() {
//constructor
}
public void SomeClass() {
//a method, NOT a constructor
}
}
Also, if a class doesn't define a constructor, then the compiler will automatically add a default constructor for you.
public void class1() is not a constructor, it is a void method whose name happens to match the class name. It is never called. Instead java creates a default constructor (since you have not created one), which does nothing.
Using void in the constructor by definition leads it to not longer be the constructor.
The constructor specifically has no return type. While void doesn't return a value in the strictest sense of the word, it is still considered a return type.
In the second example (where you use the void), you would have to do h.class1() for the method to get called because it is no longer the constructor. Or you could just remove the void.
This is arguably a design flaw in Java.
class MyClass {
// this is a constructor
MyClass() {...}
// this is an instance method
void MyClass() {...}
}
Perfectly legal. Probably shouldn't be, but is.
In your example, class1() is never getting called, because it's not a constructor. Instead, the default constructor is getting called.
Suggestion: familiarize yourself with Java naming conventions. Class names should start with uppercase.
The reason the constructor doesn't return a value is because it's not called directly by your code, it's called by the memory allocation and object initialization code in the run time.
Here is an article explaining this in greater detail:
https://www.quora.com/Why-is-the-return-type-of-constructor-not-void-while-the-return-type-of-a-function-can-be-void
I'm extending from an abstract class named ChildClass, it has 4 constructors which should be implemented.
There is a set of general configuration common to all constructors.
I could abstract these tasks and call it in all constructors.
Is there anyway to call a specif method when an object is going to be initialized rather than calling it in all of the constructor signatures?
Since Java compiler must ensure a call to a constructor of the base class, you can place the common code in a constructor of your abstract base class:
abstract class BaseClass {
protected BaseClass(/*put arguments here*/) {
// Code that is common to all child classes
}
}
class ChildClassOne extends BaseClass {
public ChildClassOne(/*put arguments here*/) {
super(arg1, arg2, ...);
// More code here
}
}
As already stated in the comment, one way to call common initialization code would be the use of this(...), i.e. you'd call one constructor from another. The problem, however, is that this call would have to be the first statement of a constructor and thus might not provide what you want.
Alternatively you could call some initialization method (the most common name would be init()) in all constructors and in a place that is appropriate (e.g. at the end of the constructor). There is one problem though: if a subclass would override that method it could create undefined situations where the super constructor calls the method and the method uses non-yet-initialized fields of the subclass. To mitigate that the method should not be overridable, i.e. declare it final or make it private (I'd prefer to have it final though because that's more explicit).
Depending on your needs there's a 3rd option: use the initializer block:
class Super {
{
//this is the initializer block that is called before the corresponding constructors
//are called so it might or might not fit your needs
}
}
Here's an example combining all 3 options:
static class Super {
{
//called before any of the Super constructors
System.out.println( "Super initializer" );
}
private final void init() {
System.out.println( "Super init method" );
}
public Super() {
System.out.println( "Super common constructor" );
}
public Super(String name) {
this(); //needs to be the first statement if used
System.out.println( "Super name constructor" );
init(); //can be called anywhere
}
}
static class Sub extends Super {
{
//called before any of the Sub constructors
System.out.println( "Sub initializer" );
}
private final void init() {
System.out.println( "Sub init method" );
}
public Sub() {
System.out.println( "Sub common constructor" );
}
public Sub(String name) {
super( name ); //needs to be the first statement if used, calls the corrsponding Super constructor
System.out.println( "Sub name constructor" );
init(); //can be called anywhere
}
}
If you now call new Sub("some name"), you'll get the following output:
Super initializer
Super common constructor
Super name constructor
Super init method
Sub initializer
Sub name constructor
Sub init method
You can declare an instance method in the class which can be called from a constructor like this:
Class A{
public A(){
initialize();
}
public void initialize(){
//code goes here
}
}
This concept extends to abstract classes as well.
You could chain your constructors.
public class Test {
public Test() {
// Common initialisations.
}
public Test(String stuff) {
// Call the one ^
this();
// Something else.
}
You can then put your common code in the () constructor.
An alternative is to use an Initializer block.
Class A {
{
// initialize your instance here...
}
// rest of the class...
}
The compiler will make sure the initializer code is called before any of the constructors.
However, I would hesitate a bit to use this use this - perhaps only if there are no other alternatives possible (like putting the code in a base class).
If you can put the common code in one constructor and call it as the first instruction from the other constructors, it is the Java idiomatic way.
If your use case is more complex, you can call a specific method from the constructors provided it is private, final or static (non overidable). An example use case would be:
class Test {
private final void init(int i, String str) {
// do common initialization
}
public Test(int i) {
String str;
// do complex operations to compute str
init(i, str); // this() would not be allowed here, because not 1st statement
}
public Test(int i, String str) {
init(i, str);
}
}
Make a common method and assign it to instance variable. Another way of doing it.
import java.util.List;
public class Test {
int i = commonMethod(1);
Test() {
System.out.println("Inside default constructor");
}
Test(int i) {
System.out.println("Inside argument Constructor ");
}
public int commonMethod(int i) {
System.out.println("Inside commonMethod");
return i;
}
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test(2);
}
}
class Yfk {
public static void main(String[] args) {
System.out.println(new YfkC().x);
}
}
abstract class YfkA {
int x = 3;
YfkA() { x++; }
}
class YfkB extends YfkA {}
class YfkC extends YfkB {}
The final result is 4. I am not clear about the extend process. In the main function, we create an object YfkC and invoke Yfkc.x. My understanding is since there is no method and filed in class yfkc, so we find in yfkb, and then find in yfkc. At this time, will YfkC be upcasted to YfkA automatically? Equal System.out.println(new YfkA().x); so we will get x = 4; I am confused about the process from YfkC to YfkA.
new YfkC().x
This internally calls the constructor of the sub class. so the value of x is incremented and printed as 4.
YfkC() -> YfkB() -> YfkA() { x++;};
The default constructor of each class is calling the super();. This calls the default constructor of the super class before executing it's own.
If you want to know about the constructor chaining then put as system out and see the calling chain.
public class Yfk {
public static void main(String[] args) {
System.out.println(new YfkC().x);
}
}
abstract class YfkA {
int x = 3;
YfkA() {
System.out.println("YfkA");
x++; }
}
class YfkB extends YfkA {
public YfkB() {
System.out.println("YfkB");
}
}
class YfkC extends YfkB {
public YfkC() {
System.out.println("YfkC");
}
}
output:
YfkA
YfkB
YfkC
4
When you invoke any Child constructor. There is a chain call to the immediate parent class constructor from the current class. And the call continues until the Object class constructor invokes since that the possible most Parent classes super class is.
Here is an example how constructor behaves in inheritance
public class ParentClass {
public ParentClass() {
System.out.println("Parent default constructor invoked");
}
public ParentClass(int a) {
System.out.println("Parent argumented constructor invoked");
}
public static void main(String[] args) {
SubSubClass sub = new SubSubClass();
}
}
class SubClass extends ParentClass {
public SubClass() {// not calling any super
System.out.println("Child default constructor invoked");
}
public SubClass(int b) {
super(b);
System.out.println("Child default constructor invoked");
}
}
class SubSubClass extends SubClass {
public SubSubClass() {// not calling any super
System.out.println("Sub Child default constructor invoked");
}
public SubSubClass(int b) {
super(b);
System.out.println("Sub Child default constructor invoked");
}
}
OUTPUT:
Parent default constructor invoked
Child default constructor invoked
Sub Child default constructor invoked
I wrote an article covering this topic, hope that clears your doubt.
Constructor inheritance(ovveriding) and reasons behind restricting constructor inheritance in Java
Whenever a child class is instantiated, its parent constructors are invoked in sequence, up the chain.
In your hierarchy, you have:
YfkC
YfkB
abstract YfkA
Object
...and in each of their constructors, there is an implicit call to super().
So, new YfkC invokes YfkB's constructor, which invokes the abstract class's YfkAs constructor, which results in the incrementation of x.
If you were to execute new YfkC().x again, you'd get 5, since every time you new up any of YfkA's children, you would be invoking that constructor.
Base Class:
public class Base {
private String baseMessage = "Hello!";
public Base() {
printMessage();
}
public void printMessage() {
System.out.println(baseMessage.toString());
}
}
Derived Class:
public class Derived extends Base {
private String derivedMessage = "World!";
public Derived () {
super();
}
#Override
public void printMessage() {
super.printMessage();
System.out.println(derivedMessage.toString());
}
public static void main(String[] args) {
// new Base();
new Derived();
}
}
When I run
new Base();
I get the expected output:
Hello!
When I Run
new Derived();
I get
Hello!
Hello!
then NullPointerException. This seems a bit weird to me. I don't know why it's printing it out then throwing a nullpointerexception, rather straight up throwing it. Maybe it's Eclipse, I don't know.
What's the underlying concept here?
Before you read this, read
What's wrong with overridable method calls in constructors?
The body of a child class constructor is compiled to something like this
public Derived () {
super();
initializeInstanceFields();
// all instance fields are initialized either to their default value
// or with their initialization expression
}
In other words, by the time the Derived#printMessage() is called because of polymorphism from the super constructor, the Derived.derivedMessage is still null.
Here's the step by step:
new Derived();
invokes the Derived constructor
public Derived () {
super();
}
which invokes the super constructor
public Base() {
printMessage();
}
Here, before the printMessage(), this class' instance fields are initialized, so baseMessage gets the value of "Hello!". When printMessage() gets invoked, because this is a Derived object and Derived overrides the methods, its implementation is invoked.
#Override
public void printMessage() {
super.printMessage();
System.out.println(derivedMessage.toString());
}
This calls the super implementation
public void printMessage() {
System.out.println(baseMessage.toString());
}
which prints
Hellow!
The method returns back to Derived#printMessage and attempts to invoke toString() on derivedMessaged, but, as I've explained earlier, the derivedMessage hasn't been initialized yet, so it is null. Dereferencing null causes NullPointerException.
And this is why you don't invoke overridable methods from constructors.
Why It calls base class method when we declare method as static in base as well as in derive class and do upcasting.
class Base
{
static void show(){
System.out.println("Base class....");
}
}
class Derive extends Base
{
static void show(){
System.out.println("Drive class....");
}//method hidding.....
public static void main(String[] args)
{
Base b= new Derive();
b.show();
}
}
There are several issues here to mention:
static methods are not inherited and not overridden by the sub-classes
static methods do not need an instance to be called, they need a class
So, basically, calling b.show(); actually means calling Base.show();
You're calling Base.show, not Derive.show. Method hiding is not overriding.
ยง8.4.8.2. of the Java Language Specification gives an example that demonstrates exactly what happens here:
A class (static) method that is hidden can be invoked by using a reference whose type is the class that actually contains the declaration of the method. In this respect, hiding of static methods is different from overriding of instance methods. The example:
class Super {
static String greeting() { return "Goodnight"; }
String name() { return "Richard"; }
}
class Sub extends Super {
static String greeting() { return "Hello"; }
String name() { return "Dick"; }
}
class Test {
public static void main(String[] args) {
Super s = new Sub();
System.out.println(s.greeting() + ", " + s.name());
}
}
produces the output:
Goodnight, Dick
because the invocation of greeting uses the type of s, namely Super, to figure out, at compile time, which class method to invoke, whereas the invocation of name uses the class of s, namely Sub, to figure out, at run-time, which instance method to invoke.
Just one more completion to the answers above. It's best to invoke class methods by their class not by an instance variable: Base.show() not b.show() to make clear that the method is a static method. This is especially useful in your case when you are hiding a method, not overriding it.