The story that the variable initialization method called in the Java constructor should not be overridden

Because it was normally used in a certain Android library.

problem

Suddenly, do you see the output of the following implementation?

public class Main {

    static class Foo {

        public Foo() {
            init();
        }

        protected void init() {
        }
    }

    static class Bar extends Foo {

        private int val1;

        private int val2 = 0;

        @Override
        protected void init() {
            val1 = 1;
            val2 = 2;
        }
    }

    public static void main(String... args) {
        Bar bar = new Bar();

        System.out.println(bar.val1);
        System.out.println(bar.val2);
    }
}

The output result is as follows.

1
0

Event

The Foo class is a constructor that calls the ʻinit ()` method.

The Bar class is a subclass of Foo, overriding the ʻinit ()method created byFoo` to initialize member variables.

In Bar.init (), the member variables val1 and val2 are assigned 1 and 2, respectively.

If you instantiate this Bar class and output each value, val1 contains 1 as you can see, but the value of val2 that should have been assigned 2 is0 It is.

A trap hidden in the initialization of member variables

There are two keys to unraveling this phenomenon.

One is the definition of member variables, and the other is the timing of variable initialization in Java.

Definition of member variables

In the code in question, the member variables of the Bar class are defined as follows:

Bar


private int val1;

private int val2 = 0;

Regarding the definition of member variables, 0 is assigned for primitives and null for classes is assigned if no explicit initialization is performed. However, even if it is initialized with 0, its behavior changes depending on whether it is explicitly initialized or not.

Java member variable initialization timing

In Java, the initialization of member variables is done in the constructor. The question is when is it happening in the constructor.

As I usually write casually, the initialization of member variables is actually done ** immediately after calling the constructor of the parent class **.

In other words

Foo


static class Foo {

    public Foo() {
← here
        init();
    }
}

is.

I don't think you can see anything, but the Java constructor requires ** calling the parent class constructor at the beginning of the constructor **. However, there is a condition that can be omitted, which is ** the parent class defines the default constructor **. The default constructor is a constructor that takes no arguments. (Strictly speaking, it doesn't have to be the parent constructor, but I'll omit it.)

So, in the code above, it's the same as having a super () call at the arrow position.

Problem description

Based on the above, I will explain the trap that I stepped on in the code in question.

It was the Bar class that took the trap.

Bar


static class Bar extends Foo {

    private int val1;

    private int val2 = 0;

    @Override
    protected void init() {
        val1 = 1;
        val2 = 2;
    }
}

If you write this class without omitting it, it will be as follows.

Bar


static class Bar extends Foo {

    private int val1;

    private int val2 = 0;

    public Bar() {
        super();
    }

    @Override
    protected void init() {
        val1 = 1;
        val2 = 2;
    }
}

The Bar constructor callssuper (), that is, the Foo constructor. The Foo constructor calls ʻinit (), which is an override of the Bar class, so it's a call to Bar.init () `.

If you expand this flow roughly

Bar() {

  super() {
    
    Bar.init() {
        Bar.val1 = 1;
        Bar.val2 = 2;
    }
  }
  
Initialization of Bar member variables() {
      Bar.val2 = 0;
  }
}

It will be the flow.

Isn't val1 initialized with 0 after super ()? You may think that, if it is not initialized at the time of definition, the initialization process itself after super () will not be performed.

Supplement

By the way, if you refer to val2 ofBar.init ()before assigning a value, 0 will be returned. Imagine that all member variables are assigned 0 or null regardless of the initialization of the member definition, and the value specified after super () is assigned.

In the first place, the implementation I posted first is the dung code, so why not use it after understanding inheritance?

reference

(It should have been officially written, but I forgot the link. If I find it, I will paste it ...)

Recommended Posts

The story that the variable initialization method called in the Java constructor should not be overridden
The story that the Servlet could not be loaded in the Java Web application
[Java] The story that the expected array was not obtained by the String.split method.
The story that the forced update could not be implemented
The story that .java is also built in Unity 2018
The case that @Autowired could not be used in JUnit5
Three reasons why wrapper classes should not be used in Java
[Gradle] The story that the class file did not exist in the jar file
[Swift] Variable shapes that were not taught in the introductory book
Call the super method in Java
Correspond to "error that basic authentication does not pass" in the test code "The story that could not be done"
I tried to solve the past 10 questions that should be solved after registering with AtCoder in Java
Map keySet, values should not be used
The story that I could not build after installing multiple Java on Windows
Using templates on the classpath with Apache Velocity
The story that the variable initialization method called in the Java constructor should not be overridden
[Android] Solution when the camera cannot be started on Android 9
[Java] When var should be used and when it should not be used
The story that the forced update could not be implemented
Solved the problem that apt-get update could not be executed on Ubuntu (Virtual Box) on Windows.
What is the main method in Java?
The story of writing Java in Emacs
About the case that ("b" .. "aa") could not be used in Ruby Range
The story that I could not build after installing multiple Java on Windows
I didn't know that inner classes could be defined in the [Java] interface
[Java] Handling of JavaBeans in the method chain
The story of making ordinary Othello in Java
A story about the JDK in the Java 11 era
[Java] Get KFunction from Method / Constructor in Java [Kotlin]
The story that the port can no longer be used in the Spring boot sample program
Java Error Handling Basics-The story that catch is only picked up in the foreground
[Java] How to omit the private constructor in Lombok
Write a class that can be ordered in Java
[Java] When var should be used and when it should not be used
[Java] Coverage report could not be created with the combination of default method of Cobertura + interface
"The Language Support for Java server crashed 5 times in the last 3 minutes. The server will not be restarted."
Shout Java at the heart of technology-Themes and elemental technologies that Java engineers should pursue in 2017-
The story that the request parameter from the iPhone application could not be obtained successfully with the Servlet
[Java 8] Sorting method in alphabetical order and string length order that can be used in coding tests
[Java] It seems that `0 <hoge <10` cannot be written in the conditional expression of the ʻif` statement.