可以参考JLS7:https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.2.3

public class Test5 {

	int a = m1();

	public int m1() {
		System.out.println(i);  // 0
		return i;
	}

	int b = (new Object() {
		public int t() {
			System.out.println(i); // 0
			return i;
		}
	}).t();

	{
		i = 100;
		System.out.println(this.i); // 100
		//i = i+1; // error Cannot reference a field before it is defined
		//System.out.println(i); // error Cannot reference a field before it is defined
	}

	//int k = i+1; // error  Cannot reference a field before it is defined

	int i = 2;

	public static void main(String[] args) {
		Test5 t = new Test5();
		System.out.println(t.i); // 2
	}

}
public class Test6 {

	static int a = m1();

	public static int m1() {
		System.out.println(i);  // 0
		return i;
	}

	static int b = (new Object() {
		public int t() {
			System.out.println(i); // 0
			return i;
		}
	}).t();

	static {
		i = j = 10;
		System.out.println(Test6.j); // 10
		//System.out.println(i); // error Cannot reference a field before it is defined
		//i = j + 2; // error Cannot reference a field before it is defined
	}

	static int i, j;

	public static void main(String[] args) {

	}

}

1、类的加载执行顺序

public class Dervied extends Base {      private String name = "dervied";       public Dervied() {           tellName();          printName();      }      public void tellName() {           System.out.println("Dervied tell name: " + name);      }      public void printName() {           System.out.println("Dervied print name: " + name);      }      public static void main(String[] args){              new Dervied();           }  }  class Base {      private String name = "base";       public Base() {          tellName();          printName();      }      public void tellName() {           System.out.println("Base tell name: " + name);      }      public void printName() {           System.out.println("Base print name: " + name);      }  }

先初始化父类然后再初始化子类(这个初始化包括静态和非静态变量、静态和非静态的方法块、构造函数)

Dervied tell name: nullDervied print name: nullDervied tell name: derviedDervied print name: dervied

再看一下如下的例子:

class ParentClass {      public static int  a=2;      public int b=3;      {          System.out.println("this is anonymity b="+b);      }      static {          a=4;          System.out.println("this is static and a="+a);      }      public ParentClass() {          System.out.println("this is parent gozao");          this.s();      }      public void s() {          System.out.println("this is parent");      }  }  public class Son extends ParentClass {      public Son(){          System.out.println("this is  son gozao");      }      public static void main(String[] args) {          ParentClass d = new Son();          d.s();      }      public void s() {          //super.s();          System.out.println("this is son");      }  }
this is static and a=4  this is anonymity b=3  this is parent gozao  this is son  this is  son gozao  this is son
可以看出类内的加载顺序为:
(1)
       静态变量   对于静态变量肯定要首先进行初始化,因为后面的方法可能会使用这个变量,或者构造函数中也可能用到。而对于非静态变量而言,由于匿名块内、非静态方法和构造函数都可以进行操作(不仅仅是初始化),所以要提前进行加载和赋默认值。
       静态代码块   多个静态代码块按顺序加载,这里需要注意:在这个顺序不难是类内书写的顺序,也是类加载的顺序,也就是说如果子类也有静态代码块,则子类的也加载。由于静态代码块可能会负责变量的初始化,或者是对象等的初始化,这样在构造函数或者方法中就变得可用了。而顺序加载多半是由于Java是按顺序执行代码的原因。
       静态方法   一般静态方法中禁止引用还未初始化的非静态变量,如果引用了静态变量,则静态变量必须放到这个静态方法的前面,以保证在使用时已经被正确地初始化。
      一般如上要按顺序执行加载。
       如果静态代码块中用到了静态变量,则静态变量必须在前面,如果在后会出现编译错误,而静态代码块中不可以出现非静态的变量。      
    public static int  a=2;  // 必须放到静态代码块前      // public int a=3;       // 代码块中会报错      {          System.out.println("this is anonymity b="+b);      }      static {          System.out.println("this is static and a="+a);      }
 静态方法与静态变量的关系和上面一样。
 
(2)
        匿名代码块  这个要后初始化于静态代码块和静态变量,因为其依然属于实例对象,而不属于类。在这里可以对非静态成员变量进行初始化工作,同样也可以引用静态变量,因为已经被初始化过了。
        非静态变量  这个要后初始化于静态代码块和静态变量,如果在匿名代码块中有对非静态变量的引用,则非静态变量必须在前面,以保证先被初始化。对静态变量的位置不做要求。举例:
    public int b=3;  // 必须放到匿名代码块的前面,以保证先被初始化后使用      {          System.out.println("this is anonymity b="+b);      }      public static int  b=2;  // 可以放到匿名代码块的任意位置
         如果两者没有引用,则按顺序执行加载。
(3)
         构造函数  这里需要解释一下,为什么初始化子类必先初始化父类,由于子类可能会继承父类的属性或方法,所以肯定要先初始化父类了,而初始化父类则必须要调用父类的构造函数。
至于方法不用考虑,因为方法不用初始化,所以无论是静态还是不静态,和这个没有关系。
其实如上的代码还能说明一些问题,可以看到,在父类中通过this.s()调用的是子类的方法,子类的s()方法覆盖了父类的方法后,无论在哪里调用,都是调用子类的方法。

下面再来看一个比较复杂的面试题(阿里巴巴),如下:

public class InitializeDemo {      private static int k = 1;      private static InitializeDemo t1 = new InitializeDemo("t1");      private static InitializeDemo t2 = new InitializeDemo("t2");      private static int i = print("i");      private static int n = 99;      static {          print("静态块");      }      private int j = print("j");            {          print("构造块");      }        public InitializeDemo(String str) {          System.out.println((k++) + ":" + str + "   i=" + i + "    n=" + n);          ++i;          ++n;      }        public static int print(String str) {          System.out.println((k++) + ":" + str + "   i=" + i + "    n=" + n);          ++n;          return ++i;      }        public static void main(String args[]) {          new InitializeDemo("init");      }  }
1:j   i=0    n=0  2:构造块   i=1    n=1  3:t1   i=2    n=2  4:j   i=3    n=3  5:构造块   i=4    n=4  6:t2   i=5    n=5  7:i   i=6    n=6  8:静态块   i=7    n=99  9:j   i=8    n=100  10:构造块   i=9    n=101  11:init   i=10    n=102

我们来解释一下:

1.     运行main方法的时候,JVM会调用ClassLoader来加载Test类,那么一起源于这次加载  2.     上面有四个静态属性,所以会按顺序逐一初始化这四个静态属性  3.private static int k = 1;                 此时将k初始化为1  4.private static Test t1 = new Test("t1");  创建Test对象,那么按照核心理念中的顺序    先执行     private int j = print("j");     打印出j,然后执行构造块,最后执行构造方法  5.private static Test t2 = new Test("t2");  同步骤4  6.private static int i = print("i");        打印i  7.private static int n = 99;                直到这一步,n才被赋值为99,之前是从默认的0开始++的  8.     静态属性初始化完毕,代码走到静态块,打印出静态块,此时n=99  9.     静态属性和静态块执行完毕,然后执行main方法中的代码new Test("init");  10.main方法中创建对象,先初始化非静态属性,private int j = print("j");打印j,然后执行构造块,最后执行构造方法

javac之向前引用的更多相关文章

  1. Java向前引用容易出错的地方

    所谓向前引用,就是在定义类.接口.方法.变量之前使用它们,例如, class MyClass { void method() { System.out.println(myvar); } String ...

  2. java向前引用

    根据看书和看得文章,引出了一个关于"向前引用"的问题: public class InstanceInitTest { static { // { a = 6; System.ou ...

  3. python自定义函数可以向前引用不用声明

    #有些编程语言不够"聪明",向这类向前引用的方式会导致报错,但Python足够"醒目",这段代码是正确的! def next():     print('我在n ...

  4. wpf staticresource 是不允许向前引用(forward reference)的

    不允许向前引用(forward reference)在C/C++中中很常见,即在语法上,未定义变量.类之前,不能使用. 没想到wpf中的wpf staticresource也遵循这种规则.资源字典中, ...

  5. 向前引用 ? float VS long ? 这些知识你懂吗?

    thinking in java 读书笔记(感悟): 作者:淮左白衣 : 写于 2018年4月2日18:14:15 目录 基本数据类型 float 和 long 谁更大 System.out.prin ...

  6. Java 9 揭秘(11. Java Shell)

    Tips 做一个终身学习的人. 在本章节中,主要介绍以下内容: 什么是Java shell JShell工具和JShell API是什么 如何配置JShell工具 如何使用JShell工具对Java代 ...

  7. 深入理解Java虚拟机类加载机制

    1.类加载时机 对于类加载的第一个阶段---加载,虚拟机没有强制的约束,但是对于初始化阶段,虚拟机强制规定有且只有以下的5中情况必须开始初始化,当然,加载.验证.准备阶段在初始化前就已经开始. ①使用 ...

  8. 《深入理解Java虚拟机》-----第7章 虚拟机类加载机制——Java高级开发必须懂的

    代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言发展的一大步. 7.1 概述 上一章我们了解了Class文件存储格式的具体细节,在Class文件中描述的各种信息,最终都需要 ...

  9. 深入理解JVM(3)——类加载机制

    1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...

随机推荐

  1. 3D 相关

    1. STL 2. AMF 3. X3D 网址: http://www.web3d.org/x3d-resources/content/examples/X3dResources.html

  2. Linux命令行下的vim文本编辑器

    Linux命令行下的vim文本编辑器 下面这个网站的地址讲解的非成分清楚!!!! http://blog.csdn.net/niushuai666/article/details/7275406 学习 ...

  3. NSIS制作安装包,如何检测并卸载已有版本

    将如下代码追加到NSIS脚本的尾部即可. Var UNINSTALL_PROG Function .onInit   ClearErrors   ReadRegStr $UNINSTALL_PROG ...

  4. ZOJ3708:Density of Power Network

    The vast power system is the most complicated man-made system and the greatest engineering innovatio ...

  5. [label][Google-Developers] Your First Multi Screen Site

    内容是任何网站最重要的部分. 所以,让我们为内容而设计,而不要让设计支配内容. 1. 首先确定我们需要的内容: 2. 基于这个内容,为无论宽.窄的 viewport 创建一个页面结构: 3. 然后在简 ...

  6. scvmm sdk之ddtkh(二)

    ddtkh,dynamic datacenter toolkit for hosters,原先发布在codeplex开源社区,后来被微软归档到开发者社区中,从本质上来说它是一个企业级应用的套件,集成了 ...

  7. js虚拟数字小键盘

    效果图 页面代码: @Html.TextBoxFor(m=>Model.FBP[i].RealNumb,new{onclick="showKeyboard('txtRealNumbOp ...

  8. RoadFlow ASP.NET Core工作流引擎IIS部署

    RoadFlow最新版本采用ASP.NET CORE2.1开发,部署步骤和.NET CORE部署一样,具体可参数ASP.NET CORE的部署方式. 1. 获取代码 首先从RoadFlow官网下载最新 ...

  9. VS2015 IIS Express 无法启动 解决办法(转)

    因为安装各种乱七八糟的软件,然后不小心把IIS Express卸载掉了,网上下载了一个IIS Express 7,安装之后本地使用VS 2015无法启动调试,F5 无法启动IIS, 再次F5调试,没有 ...

  10. Android 推送

    安卓推送方案及比较 http://www.eoe.cn/news/11955.html ******************************************************** ...