The Java constructor is not so intuitive. Or maybe it's not Java, it's C #, which is not intuitive

Given this Java code, this outputs 0 and 4 :

class A{ A() { print(); } void print() { System.out.println("A"); } } class B extends A{ int i = Math.round(3.5f); public static void main(String[] args){ A a = new B(); a.print(); } void print() { System.out.println(i); } } 

And with this identical C # code, it outputs 4 and 4

using System;

 class A{ internal A() { print(); } virtual internal void print() { Console.WriteLine("A"); } } class B : A{ int i = (int) Math.Round(3.5f); public static void Main(string[] args){ A a = new B(); a.print(); } override internal void print() { Console.WriteLine(i); } } 

Although I understand that the output should be 4 and 4 in Java, but in fact the answer is 0 and 4 in Java. Then I tried it in C #, answer 4 and 4

What gives? The rationale for Java is that when building, BA is still initialized (hence, I suppose B is still initialized if Java says that A is still initialized), so the default value should be 0. Therefore, the output is 0 and 4 in Java.

Why is the behavior of the C # constructor different from Java, or vice versa?

+6
source share
2 answers

This is due to differences in the ordering of the initialization of the object in the constructors.

What happens in Java:

  • (empty, implicit) Constructor B is called
  • The superclass Construtor of A is called (outputs 0, since I am not initializing)
  • I am initialized after the constructor of the superclass
  • print () is called (prints 4)

What happens in C #:

  • (empty, implicit) Constructor B is called
  • I am initialized before calling the superclass constructor
  • Called by the superclass Construtor of A (prints 4 since I'm already initialized)
  • print () is called (prints 4)

Wrong or wrong - it's just the difference in how the compiler orders construction operations. Personally, I think that the order of Java is a bit more logical, because it makes sense to me that the superclass is completely constructed before the subclass is initialized.

In any case, since the logic can become quite complex, I would advise you to avoid invoking virtual methods when building an object in general.

+8
source

Initialization order in Java:

1. Instance storage is destroyed to zero, automatically setting all primitives in the object to default values ​​(zero for numbers and equivalent for booleans and char) and references to zero.

2. The constructor of the base class A called. This will call the print method in class B , since it is an overridden method. i is 0 at this moment.

3. The member of class B is initialized. So, i now 4.

In order not to cause such a surprise, do not call non-static or non-private methods in the constructor, as they can be overridden in derived classes.

+1
source

Source: https://habr.com/ru/post/915869/


All Articles