Order of execution in Java - java

I am trying to understand this example from Thinking in Java:
package c07;
import com.bruceeckel.simpletest.*;
class Meal {
Meal() { System.out.println("Meal()"); }
}
class Bread {
Bread() { System.out.println("Bread()"); }
}
class Cheese {
Cheese() { System.out.println("Cheese()"); }
}
class Lettuce {
Lettuce() { System.out.println("Lettuce()"); }
}
class Lunch extends Meal {
Lunch() { System.out.println("Lunch()"); }
}
class PortableLunch extends Lunch {
PortableLunch() { System.out.println("PortableLunch()");}
}
public class Sandwich extends PortableLunch {
private static Test monitor = new Test();
private Bread b = new Bread();
private Cheese c = new Cheese();
private Lettuce l = new Lettuce();
public Sandwich() {
System.out.println("Sandwich()");
}
public static void main(String[] args) {
new Sandwich();
monitor.expect(new String[] {
"Meal()",
"Lunch()",
"PortableLunch()",
"Bread()",
"Cheese()",
"Lettuce()",
"Sandwich()"
});
}
}
As I understand from Java Language Specification, the order of execution begins by loading the class containing the main method. Then all the statics and member variables of this class must be initialized (before which all the member variables of the superclasses must be intialized, although there are none of those in this case).
So I thought b, c, l would be initialized before main starts executing. That does not seem to be the case from the output though. Am I missing something?

No, b and c are instance variables.
There's no automatic instantiation of the class containing main. Only static variables are initialized. It's just as if some outside caller wrote:
Sandwich.main(args);
So when you wrote:
Then all the statics and member variables of this class must be initialized
... that was wrong. Only the static variables are initialized - just as normal.

The example output is correct. Here are the important rules:
when the class is created, the constructor of the super class has to be called first. This bubbles up to Object class
before the constructor is called, member variable initialization is called.
No statics are involved in this example, except the technical monitor.

JLS # 12.4.1. When Initialization Occurs
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
T is a class and an instance of T is created.
T is a class and a static method declared by T is invoked.
A static field declared by T is assigned.
A static field declared by T is used and the field is not a constant
variable (§4.12.4).
T is a top level class (§7.6), and an assert statement (§14.10)
lexically nested within T (§8.1.3) is executed.
JLS # 12.5. Creation of New Class Instances
Whenever a new class instance is created, memory space is allocated for it with room for all the instance variables declared in the class type and all the instance variables declared in each superclass of the class type, including all the instance variables that may be hidden (§8.3).

Related

Why do I get an NPE when a nested Enum references a parent static member in its constructor?

Conditions to recreate (as far as I can tell):
nested enum references a parent static member
nested class
static member of parent class takes enum as an constructor argument to nested class
enum is referenced by an external class before anything else in the parent class
Run this code online:
https://repl.it/repls/PlushWorthlessNetworking
import java.util.ArrayList;
class Recreate {
private static ArrayList FEATURES = new ArrayList();
public enum Car {
TESLA(FEATURES);
Car(ArrayList l) { }
}
public static class Garage {
final Car car;
Garage(Car car) {
this.car = car;
}
}
public static Garage ONE_CAR_GARAGE = new Garage(Car.TESLA);
}
class Main {
public static void main(String[] args) {
// inclusion of this line causes the next line to NPE
System.out.println(Recreate.Car.TESLA);
System.out.println(Recreate.ONE_CAR_GARAGE.car.toString());
}
}
Here is what is happening:
The main method starts executing
You refer to Recreate.Car.TESLA
The classloader starts to load and initialize enum Car. As noted below, class Recreate is NOT yet loaded or initialized.
The initializer for TESLA refers to FEATURES
This causes class Recreate to be loaded and initialized
As part of static initialization of Recreate, Class Garage is loaded, intialized, and the instance ONE_CAR_GARAGE is created.
The problem here is that at this point, the construction of enum Car is not complete, and Car.TESLA has the value null.
Even though classes may be nested, it is not the case that nested classes are loaded and initialized as part of the outer class initialization. They may look nested in the source but each and every class is independent. Static nested classes are equivalent to top-level classes. Non-static classes are also the same but have the ability to refer to members in the containing class via a hidden reference.
You can see for yourself if you run this in a debugger, put breakpoints in several places, and examine the stack at each breakpoint.
I tested/debugged this in Eclipse with the following code, with breakpoints set where indicated. It's slightly different from your code but shouldn't behave differently:
public class Foo5
{
static class Recreate {
private static ArrayList FEATURES = new ArrayList();
public enum Car {
TESLA(FEATURES);
Car(ArrayList l) {
System.out.println("car"); // *** Breakpoint ***
}
}
public static Garage ONE_CAR_GARAGE = new Garage(Car.TESLA);
public static class Garage {
final Car car;
Garage(Car car) {
this.car = car; // *** Breakpoint ***
}
}
}
public static void main(String[] args) throws Exception {
Recreate.Car car = Recreate.Car.TESLA;
System.out.println(Recreate.Car.TESLA);
System.out.println(Recreate.ONE_CAR_GARAGE.car.toString());
}
}
The first breakpoint you will hit will be the one in the Garage(Car car) constructor. Examining the stack at that point you will see
Foo5$Recreate$Garage.<init>(Foo5$Recreate$Car) line: 23
Foo5$Recreate.<clinit>() line: 17
Foo5$Recreate$Car.<clinit>() line: 12
Foo5.main(String[]) line: 29
So when the Garage constructor is called, it has not yet returned from creating Car. This is dictated by the convoluted dependencies you have created between classes, so the solution is to untangle the dependencies. How you do that will depend on your ultimate goals.
You have a hidden circular dependency that's confusing the JVM. Let's take a look at your code.
class Recreate {
private static ArrayList FEATURES = new ArrayList();
public enum Car {
TESLA(FEATURES);
Car(ArrayList l) { }
}
public static class Garage {
final Car car;
Garage(Car car) {
this.car = car;
}
}
public static Garage ONE_CAR_GARAGE = new Garage(Car.TESLA);
}
We'll also need a few snippets from a page out of the JLS.
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
A static field declared by T is used and the field is not a constant variable (§4.12.4).
12.4.2. Detailed Initialization Procedure
...
Next, execute either the class variable initializers and static initializers of the
class, or the field initializers of the interface, in textual order, as though they
were a single block.
So our static data is being initialized when it's first referenced. Now, your Car.TESLA is implicitly static final, but it's not a constant, as per the definition.
A constant variable is a final variable of primitive type or type String that is initialized with a constant expression
So for our purposes, there are three static non-constant variables in play here: FEATURES, TESLA, and ONE_CAR_GARAGE.
Now, in your working case, you reference Recreate.ONE_CAR_GARAGE. This is a reference to a static field in Recreate, so FEATURES and then ONE_CAR_GARAGE get initialized. Then, during the initialization of ONE_CAR_GARAGE, TESLA gets initialized since its enumeration class is referenced. All's well.
However, if we reference the enum too early then we do things in the wrong order. Recreate.Car.TESLA gets referenced, so TESLA gets initialized. TESLA references FEATURES, so Recreate has to be initialized. This causes FEATURES and ONE_CAR_GARAGE to get initialized before TESLA finishes existing.
It's that hidden dependency that trips you up. Recreate.Car depends on Recreate which depends on Recreate.Car. Moving the ONE_CAR_GARAGE field into the Garage class will cause it to not get initialized with FEATURES and will fix your problem.

Accessing parent class static field using child class name doesn't load the child class?

class A {
static int super_var = 1;
static {
System.out.println("super");
}
}
class B extends A {
static int sub_var = 2;
static {
System.out.println("sub");
}
}
public class Demo{
public static void main(String []args){
System.out.println(B.super_var);
}
}
outputs are :
super
1
this means that the child class not going to load or any other thing? how is it works?
When you access the static fields of a super class on subclass reference, only the class that declares the field will be loaded and initialized, in this case it is A. This is specified in JLS §12.4.1 - When Initialization Occurs:
A reference to a static field (§8.3.1.1) causes initialization of only
the class or interface that actually declares it, even though it might
be referred to through the name of a subclass, a subinterface, or a
class that implements an interface.
Emphasis mine.
So in your code, class B would not even be initialized, and hence its static block would not be executed.
Checkout the answer to this question: In what order do static initializer blocks in Java run?
The static block gets called only when a class is accessed (either creating an instance or accessing a member field or static method). However, you access a member of class A only, so there is no reason for class B to be initialized yet. The static initializer of B will be called as soon as you access a member from that class (either a field or static method, or create an instance from class B).
The reason is that class B doesn't need to be initialized until you access one of its members. Because A doesn't know about B (and cannot access it) there's really no reason for B to initialize at that stage.
You will find out that when you access B.sub_var the static initializer of B will be executed.

static keyword in Java

class A {
static {
System.out.println("A-SIB");
}
static void test(){
System.out.println("A-test");
}
}
class B extends A {
static {
System.out.println("B-SIB");
}
}
class C {
public static void main(String args []){
B.test();
}
}
When I ran class C, I thought A-SIB, B-SIB and A-test will be printed, but B-SIB was not there in the output. Can somebody explain why?
Here's what the JLS says about class initialization:
Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.
Initialization of an interface consists of executing the initializers for fields (constants) declared in the interface.
Before a class is initialized, its direct superclass must be initialized, but interfaces implemented by the class are not initialized. Similarly, the superinterfaces of an interface are not initialized before the interface is initialized.
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
T is a class and an instance of T is created.
T is a class and a static method declared by T is invoked.
A static field declared by T is assigned.
A static field declared by T is used and the field is not a constant variable (§4.12.4).
T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface.
In this case, All you do in C with the class B is call the static method test(). But this method is declared in A, not in B. Thus, the JVM doesn't initialize the class B and thus doesn't invoke its static initializer block.
Note that the class B is referenced in C's byte-code and is loaded by the JVM. But it's not initialized. If you delete B.class and try to run C, you'll get an exception.
Class B does not implement (aka "hide") the static test method, so initial execution begins within Class A (hence A-SIB); and then with the test method in A (hence "A-test"). If you override test in Class B, you will get A-SIB B-SIB B-test

How is it possible to create instance outside class of local inner class having private constructor?

Consider the following program:
public class A
{
public static void main(String[] args)
{
class B
{
private B()
{
System.out.println("local");
}
}
// how are we able to create the object of the class having private constructor
// of this class.
B b1= new B();
System.out.println("main");
}
}
Output:
local
main
A class having private constructor means we can create object inside the class only, but here am able to create instance outside the class. can someone explain how are we able to create the object of B outside class B??
Because a Top Level Class is a happy family, everyone can access one another despite private.
JLS 6.6.1
6.6.1. Determining Accessibility
A member (class, interface, field, or method) of a reference (class, interface, or array) type or a constructor of a class type is accessible only if the type is accessible and the member or constructor is declared to permit access:
Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
You're allowed to even access private variables of that class too (try it!).
This is because you are defining that class inside the same class your calling it from, so you have private/internal knowledge of that class.
If you move Class B outside of Class A, it will work as expected.
Refer the JLS 6.6.1:
Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
The way this is implemented is using synthetic package-protected methods.
"If you like to hide the private members of your inner class, you may define an Interface with the public members and create an anonymous inner class that implements this interface. Refer to this code:"
class ABC{
private interface MyInterface{
public void printInt();
}
private static MyInterface mMember = new MyInterface(){
private int x=10;
public void printInt(){
System.out.println(String.valueOf(x));
}
};
public static void main(String... args){
System.out.println("Hello :: "+mMember.x); ///not allowed
mMember.printInt(); // allowed
}
}
You said that
A class having private constructor means we can create object inside the class only
But
Thats happened because you define your inner Class in main(String[] args) method Not in Top Level Class
If you try that
public class A {
class B {
private B() {
System.out.println("local");
}
}
public static void main(String[] args) {
B b1 = new B(); // you cant create object of inner Class B
System.out.println("main");
}
}
Then you cant create object of inner Class B

Effective java Item no 74(on serialization): Implement Serializable judiciously

It item no 74 of effective java book there is a paragraph (2nd para from last of the item 74) which mentions as per below:
Inner classes (Item 22) should not implement Serializable. They use
compiler-generated synthetic fields to store references to enclosing
instances and to store values of local variables from enclosing
scopes. How these fields correspond to the class definition is
unspecified, as are the names of anonymous and local classes.
Therefore, the default serialized form of an inner class is ill-
defined.
I know about inner class uses compiler generated synthetic field to store reference to enclosing instances e.g. if the enclosing class is MyEnclosing and inner class is MyInner then the enclosing reference is MyEnclosing.this. But i am not able to get the BOLD part. Please help me getting the meaning. Thanks!!!
Suppose you have a local class like this:
class OuterClass {
Runnable run;
void method() {
final int a = 8;
this.run = new Runnable() {
public void run() {
System.out.println(a);
}
};
}
}
Now suppose I try to serialize this, which contains an object of this inner class type. My compiler names that class OuterClass$1 and gives it a field called val$a. But the exact names to be used in this situation are not part of the compiler's spec. Another compiler might choose to call the inner class OuterClass$method$1. In that case, serializing in one compiled version and deserializing in the other would fail, even though the same source file was used.
(Plus, there's also the problem that an anonymous inner class does not have a no-args constructor. But due to the problem above, even a named inner class cannot reliably serialize)
Consider the following code:
public class Main {
public static void main(String[] args) {
final int x = Integer.valueOf(args[0]);
new Object() {
void print() {
System.out.println(x);
}
}.print();
}
}
My compiler calls the anonymous inner class Main$1. When I disassemble it, I see that a copy of the value of x from the outer scope is stored in a private field called val$x:
private final int val$x;
This is an example of what the bold part is talking about.
An inner class is a non-static class defined within some other class:
class Outer implements Serializable {
private String someString;
class Inner implements Serializable {
private int someInt;
}
}
Once you have an instance of the Inner class, when you serialize it, it must have a reference to the outer class (which it accesses internally via the Outer.this reference) and how this is achieved for a serialized object is unspecified. The same applies to a local class:
class Outer implements Serializable {
private String someString;
Serializable method(final int i) {
class Inner implements Serializable {
Inner() {
System.out.println(i);
}
}
return new Inner();
}
}
If you serialize the value returned by method(), it would need to have a reference to i, but that's not reliable.

Categories

Resources