Objective
In Java, an object must be properly initialized before it can be used, as specified by the Java specification. Recently I found an interesting question, the answer to this question at first glance cheated my eyes. Take a look at these three categories:
Package com.ds.test;
public class Upper {
String upperstring;
Public Upper () {
initializer.initialize (this);
}
}
Package com.ds.test;
public class Lower extends Upper {
String lowerstring = null;
Public Lower () {
super ();
System.out.println ("Upper:" + upperstring);
System.out.println ("Lower:" + lowerstring);
}
public static void Main (final string[] args) {
new Lower ();
}
}
Package com.ds.test;
public class initializer {
static void Initialize (final Upper anupper) {
if (anupper instanceof Lower) {
Lo Wer lower = (lower) anupper;
lower.lowerstring = "lowerinited";
}
anupper.upperstring = "upperinited";
}
}
Lower
What output can I get from running this class? It is easier to see the whole situation in this minimalist example, but in reality there is a lot of code that distracts one's attention.
Anyway, the output is like this:
upper:upperinited
Lower:null;
Although the type is used in the small example String
, the Initializer
actual code of the class has a delegate object for registration that is the same as the Lower
function of the class-at least the Lower
class is the intent. However, for some reason it is not working when you run the application. Instead, the default path is used, and the delegate object is not set (null).
Now change Lower
the code a little bit:
Package com.ds.test;
public class Lower extends Upper {
String lowerstring;
Public Lower () {
super ();
System.out.println ("Upper:" + upperstring);
System.out.println ("Lower:" + lowerstring);
}
public static void Main (final string[] args) {
new Lower ();
}
}
Now the output is like this:
upper:upperinited
lower:lowerinited
Do you see the difference in the code?
Yes, this lowerString
field is no longer explicitly set to NULL. Why does this have to be different. Anyway is the default value for the Reference type field (for example, here String
) not empty? Of course it's empty. It turns out that although this slight change obviously doesn't change the behavior of the code in any way, it makes the results different.
So, what's going on? When you look at the initialization order, everything becomes clear:
1. main()
The function calls the Lower
constructor.
2. Lower
An example is prepared. means that all fields are created and the default values are populated, for example, the default value for the reference type is NULL, and the default value for the Boolean type is false
. At this point, any inline assignment to the field does not occur.
3. The parent class constructor was invoked. This is enforced by the characteristics of the language. So before anything else happens, the Upper constructor is invoked.
4.Upper This constructor runs and specifies a reference that points to the Initializer.initialize()
newly created instance of the method.
5. Initializer
the class is attached with a new string of two fields ( upperString
and lowerString
). Assigning values to those two fields by using a bit of a dirty instanceof
instance check-this is not a particularly good design pattern, but it is also feasible, not so much. Once it happens, upperString
lowerString
the references are no longer empty.
6. Initializer.initialize()
The call completes, the Upper
constructor is also completed.
7. Now it becomes interesting: Lower
The construction of the instance continues. Assuming lowerString
there is no explicit assignment in the declaration of the field =null
, the Lower
constructor resumes execution and prints out two strings connected to the field.
However, if there is an explicitly assigned null operation, the execution process is slightly different: when the parent class constructor completes, any variable initialization executes (see the Java Language Specification section 12.5) before the remaining constructors run. In this case, the lowerString
string reference that was assigned before will not be assigned null again. Then continue with the rest of the function constructs, and now lowerString
the printed value is: null.
This is a good example of how we can pay attention to the details of creating objects (or where to look at Java coding specifications, print or online) and why it's bad to write initialization like this. We should not care about Upper subclasses at all. Conversely, if initialization of some fields for some reason cannot be done in the subclass itself, it will only need some variant of its own initialization help class. In this case, if you use String lowString
or String lowerString = null
really make no difference, what it should be.
Summarize
The above is the entire content of this article, I hope this article content for everyone's study or work can bring some help, if there are questions you can message exchange.