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
    

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

  • 相关阅读:
    linux 7版本配置端口转发
    修改/etc/hosts.allow和/etc/hosts.deny允许linux服务器允许和限制访问策略
    DNS解析全过程
    zabbix监控原理和架构详谈
    数据库连接池
    Haproxy负载均衡
    Redis数据库
    Tensorflow实战第十一课(RNN Regression 回归例子 )
    OneNote2016代码高亮插件的安装与使用
    Tensorflow实战第十课(RNN MNIST分类)
  • 原文地址:https://www.cnblogs.com/chafanbusi/p/10641184.html
Copyright © 2011-2022 走看看