简体   繁体   中英

Initialization of final fields

Can somebody explain to me behaviour of this example:

package test;

public class Test {

    static abstract class Parent{

        public Parent() {
            print();
        }
        public abstract void print();
    }

    static class Child extends Parent{

        protected final int i= 10;

        public Child() {
            super();
        }
        public void print(){
            System.out.println(i);
        }
    }

    public static void main(String[] args) {
        System.out.println("Test");
        new Child();

    }

}

Output of this snippet is 10 . But when I change variable i to any object, for example Integer, output is null . But when I change i to static Integer output is 10 as expected.

I thougth that fields are initialized before any method (or constructor) is called, but here this approach works just with primitive types and not objects.

Thanks

Radim

Instance fields of a class are initialized directly after the super() call in the constructor, whether they are final or not. However, super() invokes the parent's class constructor, which reads the value of the therefore uninitialized field.

Static fields of a class are initialized when the class is referenced at runtime, which implies that static fields are initilized before a constructor of a class gets called (before the super() call in the class's constructor).

The explanation, why 10 was still printed, when the fields type was int is, that the Java compiler may inline the value of final fields at compile time. In that case, the program never reads the value of the field since the compiler optimized the code such that it looks like System.out.println(10) instead of System.out.println(i) . Under which circumstances the Java compiler inlines final fields is not defined, however, it is likely to do so for primitive field types and unlikely for most Object types.

Non Static Member :

new Child() triggers constructor chaining in this order Parent() --> Child().

While Parent object gets instantiated you are calling print(), as it hold reference of Child Object it will call

public void print(){
            System.out.println(i); 
        }

as child initiation still not complete at this stage. Integer i do not have any value hence it will print null .

Static variable :

Static data member are initialized as soon as corresponding class has been referred/envoked hence it will print 10 .

Instance Fields of child are not initialized when parent constructor is called

This is because of the logic that Parent should exist before the existance of Child .

So the constructor of Parent is called first and during that time none of the fields of Child are initialized.

Hence when you call print() that is overridden by Child , the uninitialized value of i is printed.

Static Fields are initialized at Class Initialization time

Are initialized at Class Initialization time which happens during class loading , so they will have the value initialized

Because of final nature of the field, it is initialized before the constructors, unlike variables. Therefore, the value is printed.

What happens when you declare final Integer i = 10 ? Or int i = 10 ?

Code for main should be

Child child = new Child();
child.print();

Then if you use int or Integer, it returns 10;

Using only

new Child()

then there is no return value to this variable and the new instance is ignored.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM