java基础回顾——浅谈java初始化

      干了接近两年的ETL和数据库运维,开发相关的东西已经忘了很多了,学了的东西还是不能丢。java基础回顾系列作为对以前学习知识的重温、记录以及分享。
      作为科班出生的,第一门编程语言就是C,曾经产生了很多由于未正确初始化导致的错误。java尽力保证所有变量在使用之前都会得到恰当的初始化(对于方法的局部变量,Java会以编译时错误的形式来提醒程序员进行初始化),但是并不意味着我们可以忽略初始化这个问题。

局部变量与类变量

      对于局部变量,如果未进行初始化就对其进行操作,会以编译时错误来提示你该变量未初始化。
      对于类的成员变量则有所不同,对于基本类型,java会给其一个默认值,对于引用类型会赋予一个null。

类型 默认值
boolean false
char ‘\u0000’
byte (byte)0
short (short)0
int 0
long 0l
float 0.0f
double 0.0d

char的默认值为unicode中的一个空字符。

初始化顺序

      在类的内部,初始化的顺序会按照变量定义的先后顺序进行初始化,之后才是构造器的调用。例如:

public class InitOrder {
    InitOrder(int order){
        System.out.println("class var "+order);
    }
}
public class OrderOfInit {

    InitOrder io1 = new InitOrder(1);

    OrderOfInit(){
        System.out.println("OrderOfInit constructor");
        io2 = new InitOrder(21);
        System.out.println("construction is done!");
    }

    public static void main(String[] args) {
        new OrderOfInit();
    }

    InitOrder io2 = new InitOrder(2);
}

OUTPUT:
class var 1
class var 2
OrderOfInit constructor
class var 21
construction is done!

      可以看到我们虽然将类变量的定义与构造器顺序打乱,但是,构造器的调用都在类变量的初始化完成之后再执行的。还注意到io的定义是在构造器定义之后的,却编译通过了。我们可以使用javac -p OrderOfInit.class查看其字节码,可以帮助我们更好的理解其中过程。

Compiled from "OrderOfInit.java"
public class initorder.OrderOfInit {
  initorder.InitOrder io1;

  initorder.InitOrder io2;

  initorder.OrderOfInit();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: aload_0
       5: new           #2                  // class initorder/InitOrder
                ......
      54: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      57: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #10                 // class initorder/OrderOfInit
       3: dup
       4: invokespecial #11                 // Method "":()V
       7: pop
       8: return
}
实例初始化

      java中也有称为实例初始化的语法,用于初始化每一个对象的非静态变量。其初始化顺序与类变量定义处于同级,在构造器调用之前执行。

public class OrderOfInit {

    InitOrder io1 = new InitOrder(1);

    // 实例初始化块
    {
        InitOrder ioBlock = new InitOrder(3);
        System.out.println("block init");
    }

    OrderOfInit(){
        System.out.println("OrderOfInit constructor");
        io2 = new InitOrder(21);
        System.out.println("construction is done!");
    }

    public static void main(String[] args) {
        new OrderOfInit();
    }

    InitOrder io2 = new InitOrder(2);
}

OUTPUT:
class var 1
class var 3
block init
class var 2
OrderOfInit constructor
class var 21
construction is done!

静态成员初始化与显示静态初始化

      静态数据与类相关与对象无关,无论创建多少对象都只占用一份存储区域。首先看看以下代码的初始化顺序。

public class StaticInit {

    public InitOrder ios4 = new InitOrder(4);

    public static InitOrder ios5  = new InitOrder(5);
}
public class StaticInit2 {
    public static InitOrder ios6  = new InitOrder(6);
}
public class OrderOfInit {

    public InitOrder io1 = new InitOrder(1);

    public static InitOrder io2 = new InitOrder(2);

    public static InitOrder io3;

    static{
        io3 = new InitOrder(3);
    }

    public InitOrder io6;

    OrderOfInit(){
        new StaticInit();
        new StaticInit();

        io6 = StaticInit2.ios6;
    }

    public static void main(String[] args) {
        new OrderOfInit();
    }
}

OUTPUT:
class var 2
class var 3
class var 1
class var 5
class var 4
class var 4
class var 6

      静态成员的初始化只有在必要的时刻才会进行,从代码中可以看到只有在创建StaticInit对象或者通过StaticInit2.ios6调用静态成员才会使其执行初始化动作。OrderOfInit()构造器中创建了两次StaticInit的对象,可以从结果看到其中的静态成员只初始化了一次。
      初始化的顺序是先初始化静态对象,而后是非静态对象。

继承关系中的初始化顺序

      在继承体系中,对象的构建过程是从基类向下扩散的,基类会在导出类构造器访问他之前就会完成初始化。

public class Car {
    public Car() {
        System.out.println("car constructor");
    }
}
public class SUV extends Car {

    private Window win = new Window("suv");
    private static Engine engine = new Engine("SUV");

    public SUV() {
        System.out.println("suv constructor");
    }
}
public class RangeRover extends SUV{

    private Window win = new Window("RangeRover");
    private static Engine engine = new Engine("RangeRover");

    public RangeRover() {
        System.out.println("Range Rover");
    }

    public static void main(String[] args) {
        new RangeRover();
    }
}
public class Engine {
    public Engine(String ids) {
        System.out.println(ids + " Init engine");
    }
}
public class Window {
    public Window(String ids) {
        System.out.println(ids + " create windows");
    }
}

OUTPUT:
SUV Init engine
RangeRover Init engine
car constructor
suv create windows
suv constructor
RangeRover create windows
Range Rover

      在继承关系中,首先基于类的继承层次一次初始化静态域。然后,根据类的继承层次向外扩散,一次初始化类中的非静态域以及调用构造器完成对象的初始化。默认子类会调用父类的无参构造器,如果父类定义了带参数的构造器,则需要在子类中显示调用父类的构造器。

初始化遇到内部类

      内部类是定义在一个类内部的类,一方面内部类可以作为一种代码的组织和隐藏机制,另一方面使得java中的多重继承机制更加完善。
      内部类在事件驱动类编程中应用比较广泛。

非静态内部类

      非静态内部类中不能包含静态域或者方法。非静态内部类的创建需要通过一个外部类的引用来创建,即首先需要获取一个外部类的对象,才能创建内部类的对象。

public class OuterClassInitOrder {
    private InitOrder io1 = new InitOrder(1);
    private static InitOrder io2 = new InitOrder(2);

    public OuterClassInitOrder() {
        System.out.println("Outer Class constructor");
    }

    private class InnerClass{
        private InitOrder ioi1 = new InitOrder(11);

        public InnerClass() {
            System.out.println("Inner Class constructor");
        }
    }

    public InnerClass f(){
        return new InnerClass();
    }

    public static void main(String[] args) {
        OuterClassInitOrder oci = new OuterClassInitOrder();
        oci.f();
    }
}

OUTPUT:
class var 2
class var 1
Outer Class constructor
class var 11
Inner Class constructor

静态内部类

      静态内部类即定义为static的内部类,其中可以包含静态或非静态的成员或方法。创建静态内部类不需要对外部类对象的引用。

public class OuterClassInitOrder {
    private InitOrder io1 = new InitOrder(1);
    private static InitOrder io2 = new InitOrder(2);

    public OuterClassInitOrder() {
        System.out.println("Outer Class constructor");
    }

    public static class InnerClass{
        private InitOrder ioi1 = new InitOrder(11);
        private static  InitOrder ioi2 = new InitOrder(22);

        public InnerClass() {
            System.out.println("Inner Class constructor");
        }
    }

    public InnerClass f(){
        return new InnerClass();
    }

    public static void main(String[] args) {
        new OuterClassInitOrder.InnerClass();
    }
}

OUTPUT
class var 2
class var 22
class var 11
Inner Class constructor

      可以看到在创建静态内部类时,会首先初始化外部类的静态域,也只会初始化外部类的静态域。然后按照静态域->非静态域->调动构造器的顺序初始化内部类。

你可能感兴趣的:(javaSE,java)