zoukankan      html  css  js  c++  java
  • 类的加载连接初始化顺序 (二)

    1.数组对象的使用,不会导致对应类的初始化。

    在创建 ClassName[]数组时,并不会创建对应对象,也不会初始化对应类,会创建一个编译时类型(其数组类型是JVM在运行时期动态生成的,不是由类加载器加载的,即没有对应的ClassLoader。调用getClassLoader会返回对用元素的ClassLoader) [+L+类全名 如下:

    public class MyTest02 {
    
    	public static void main(String[] args) {
    		Sub[] subs = new Sub[1];
    		Sub[][] subss = new Sub[1][1];
    		String[] strs = new String[1];
    		int[] is = new int[1];
    		char[] chars = new char[1];
    		byte[] bs = new byte[1];
    		boolean[] bo = new boolean[1];
    		System.out.println("Sub[]'s class is       "+subs.getClass());
    		System.out.println("Sub[][]'s class is     "+subss.getClass());
    		System.out.println("Sub[]'s father's class "+subs.getClass().getSuperclass());
    		System.out.println("String[]'s class is    "+strs.getClass());
    		System.out.println("int[]'s class is       "+is.getClass());
    		System.out.println("char[]'s class is      "+chars.getClass());
    		System.out.println("byte[]'s class is      "+bs.getClass());
    		System.out.println("boolean[]'s class is   "+bo.getClass());
    	}
    
    }
    class Sub{
    	static {
    		System.out.println("Sub static block");
    	}
    }
    //~out:
    Sub[]'s class is       class [Ljvm.Sub;
    Sub[][]'s class is     class [[Ljvm.Sub;
    Sub[]'s father's class class java.lang.Object
    String[]'s class is    class [Ljava.lang.String;
    int[]'s class is       class [I
    char[]'s class is      class [C
    byte[]'s class is      class [B
    boolean[]'s class is   class [Z
    

     特别的 这些数组的父类为Object,二维数组则多加一个[符号。

    2.初始化中各字段初始化的先后顺序

    关于类初始化的复制顺序 如下代码的输出结果应该很好判断

    public class MyTest03 {
    
    	public static void main(String[] args) {
    		;
    		System.out.println("Singleton.value1 = "+Singleton.getInstance().value1);
    		System.out.println("Singleton.value2 = "+Singleton.getInstance().value2);
    
    	}
    	
    
    }
    class Singleton{
    	public static int value1;
    	public static int value2 = 0;
    	private static Singleton instance = new Singleton();
    	Singleton(){
    		value1++;
    		value2++;
    	}
    	public static Singleton getInstance() {
    		return instance;
    	}
    	
    }//~out:

    Singleton.value1 = 1
    Singleton.value2 = 1

     但我们调整一下static域字段的定义顺序:

    public class MyTest03 {
    	public static void main(String[] args) {
    		System.out.println("Singleton.value1 = "+Singleton.getInstance().value1);
    		System.out.println("Singleton.value2 = "+Singleton.getInstance().value2);
    	}
    	
    
    }
    class Singleton{
    	private static Singleton instance = new Singleton();
    public static int value1; public static int value2 = 0; Singleton(){ value1++; value2++; } public static Singleton getInstance() { return instance; } }//~out: Singleton.value1 = 1 Singleton.value2 = 0

    会发现value2在自增后又被初始化为零了,而value1没有,static域的对象初始化的顺序是依照源文件声明的顺序初始化的,

    连接阶段准备阶段会为静态域赋初值(int为0)

    初始化阶段依照声明顺序,先初始化instance引用对象,调用Singleton构造函数 此前value1,value2的值在连接阶段被初始化为默认值0.

    调用后各自增了1 然后再初始化value1,value2的值,因为value1未被赋初值,故不进行操作,value2的值为1。

    ==================================可不看=======================================================public class MyTest0 public static void main(String[] args) {  Singleton.getInstance(); }

    	
    
    }
    class Singleton{
    	
    	private static Singleton instance = new Singleton();
    	public Sub sub1;
    	public Sub sub2 = new Sub("sub2");
            {
      sub1 = new Sub("123");
         } public Sub sub3 = new Sub("sub3"); Singleton(){ sub1 = new Sub("sub1"); System.out.println("creating"); } public static Singleton getInstance() { return instance; } } class Sub{ Sub(String str){ System.out.println(str); } }//~out:
    sub2
    123 sub3
    sub1 creating

     类成员对象的初始化也依照定义顺序

    ==============================================================================================

    3.接口的初始化

    接口中所有字段均为 public static final

    public class MyTest04 {
    	MyTest04(String str){
    		System.out.println(str);
    	}
    	public static void main(String[] args) {
    		System.out.println(Father04.str);
    		System.out.println(Child04.str);
    
    	}
    
    }
    interface Father04{
    	String str = "Father04";
    }
    interface Child04 extends Father04{
    	String str = "Child04";
    }//~out:
    Father04
    Child04
    

    编译后就算把接口的字节码删除依然不会报错,

    static final的字段由于是编译时常量 被写入了MyTest04的常量池中,所以不会首次主动使用Father04。

    JVM规范允许类加载器在预料到某个类将要被使用时就预先加载它,如果在预先加载时遇到了.class文件缺失或者存在错误,类加载器必须在程序首次主动使用时才报告错误(LinkageError错误)

    public class MyTest04 {
    	public static void main(String[] args) {
    		Child04.sub.toString();
    
    	}
    
    }
    interface Father04{
    	String str = "Father04";
    	Sub sub = new Sub("father");
    }
    interface Child04 extends Father04{
    	String str = "Child04";
    
    	Sub sub = new Sub("child");
    }
    class Sub{
    	Sub(String str){
    		System.out.println(str);
    	}
    }
    //~out:child
    

    初始化子接口时,并不会初始化其父接口

  • 相关阅读:
    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
    11
    实战 迁移学习 VGG19、ResNet50、InceptionV3 实践 猫狗大战 问题
    tx2系统备份与恢复
    如何在Ubuntu 18.04上安装和卸载TeamViewer
    bzoj 3732 Network (kruskal重构树)
    bzoj2152 聪聪可可 (树形dp)
    牛客 216D 消消乐 (二分图最小点覆盖)
    牛客 197E 01串
    Wannafly挑战赛23
  • 原文地址:https://www.cnblogs.com/chafanbusi/p/10641184.html
Copyright © 2011-2022 走看看