First, let’s figure out static properties and static methods in Java.

Common questions about statics

Here I ask a few questions for you to think about and see if you can answer them in a second.

  • 1. Can static properties be inherited?
  • 2. Can static methods access non-static properties?
  • 3. Can non-static methods access static properties?
  • 4. Can static methods use the this/super keyword?
  • 5. Why can’t static methods call non-static methods or variables?
  • 6. What is the order in which static properties, non-static properties, static blocks, non-static blocks, and constructors are initialized?

Answer first:

  • Private public protected (private public protected)
  • 2. No, I can’t
  • 3. Yes, because static variables are stored in static memory cells and can be called directly from classes or referenced by instantiated objects. So non-static methods can refer to static variables
  • 4. No, this refers to the current object, and super refers to the parent object. Static methods belong to a class, not an object, and the object may not exist when the static method is loaded. If you have this and super in a static method then when the static method is loaded into memory, and this and super are loaded into memory, but the object hasn’t been created yet and this and super haven’t been initialized yet, so it’s going to be loaded with an error.
  • 5. Static methods belong to a class and do not need to be instantiated. They do not belong to an object, whereas non-static variables belong to an object and need to be instantiated first. Accessing a non-static member in a static method of a class is an error because the static property of the class already exists when the non-static member of the class does not exist. Of course, accessing something that does not exist in memory will cause an error.
  • 6. Regardless of inheritance, static properties and blocks (in the order in which the code appears) > Non-static properties and blocks > Constructors

Let’s verify that in a second

Public class StaticDemo {public String b = "non-static demo "; Public static String a = "static "; static { System.out.println(a); System.out.println(" static code block "); } { System.out.println(b); System.out.println(" non-static code block "); } public StaticDemo() {system.out.println (" constructor "); } public static void main(String[] args) { StaticDemo demo = new StaticDemo(); }}Copy the code

Print result:

Static property Static block non-static property Non-static block constructorCopy the code

In the case of inheritance

Static properties and static blocks of the parent class > Static properties and static blocks of the child class > Non-static properties of the parent class > constructor of the parent class > Non-static functions of the child class > constructor of the child class

Let’s verify that again

Class ParentClass{public static String pA = "ParentClass "; Public String pB = "superclass - non-static property "; static { System.out.println(pA); System.out.println(" parent class - static code block "); } { System.out.println(pB); System.out.println(" parent class - non-static code block "); } public ParentClass() {system.out.println (" superclass-constructor "); }} public String extends ParentClass; public String extends ParentClass; Public static String a = "static "; static { System.out.println(a); System.out.println(" static code block "); } { System.out.println(b); System.out.println(" non-static code block "); } public StaticDemo() {system.out.println (" constructor "); } public static void main(String[] args) { StaticDemo demo = new StaticDemo(); }}Copy the code

Execution result:

Parent - Static property Parent - Static block Static property Static block Parent - Non-static property Parent - Non-static block constructor Non-static property Non-static block constructorCopy the code

We know the answers to these questions, but why?

How are classes loaded

Let’s look at the class loading process:

Graph TD load --> verify --> Prepare --> parse --> initialize

The process in the flowchart is a class loading lifecycle, with each phase doing its work

  1. Loading: Three main things were done:
  • Get the binary byte stream, that is, find out where the class is by its fully qualified name. Is it a JAR or a class file
  • Convert a static storage structure into a method area runtime data structure
  • Generate a class object (equivalent to a handle, access to the method area) in the Java heap to access the method area
  1. Validation: mainly is to verify the correctness of the class, including magic number, version number, constant pool validation, metadata validation, bytecode validation, symbol reference validation and so on
  2. Preparation: Allocates memory for class variables and sets initialization of class variables. This memory is allocated in the method area. Notice that memory is allocated for our class variables, which are static variables, but not for our ordinary member variables.

It is also important to note that final modified class variables are assigned during the preparation phase

static int n = 2; Static final int n = 2; static final int n = 2; static final int n = 2; // The initial value is 2. ConstantValue corresponds to the constant pool. N is assigned to 2 during the preparation phaseCopy the code
  1. Parse: Parse a symbolic reference. Direct reference: a pointer or offset to a target. Converts a symbolic reference to a direct reference
  2. Initialization: When compiling a class file, two methods are automatically generated, one is the class initialization method < clinit> and the other is the instance initialization method < init>.
  • The initialization phase of the < init > method instance
  • < clinit > method static variable, static block initialization (if there is no static block, static variable, no method)
Class A{// initialize static int I = 2; //clinit static { System.out.print(""); } int n; }Copy the code

Static methods belong to the class and are allocated memory when the class is loaded and can be accessed directly by the class name. Non-static members (variables and methods) belong to an object of a class, so they exist only after the object is initialized and then accessed through the object of the class.

That is, if we call a non-static member variable in a static method, we get ahead of ourselves, and we might call a variable that hasn’t been initialized yet. Therefore, the compiler will report an error.