javac之向前引用
可以参考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
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); }
public int b=3; // 必须放到匿名代码块的前面,以保证先被初始化后使用 { System.out.println("this is anonymity b="+b); } public static int b=2; // 可以放到匿名代码块的任意位置
下面再来看一个比较复杂的面试题(阿里巴巴),如下:
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之向前引用的更多相关文章
- Java向前引用容易出错的地方
所谓向前引用,就是在定义类.接口.方法.变量之前使用它们,例如, class MyClass { void method() { System.out.println(myvar); } String ...
- java向前引用
根据看书和看得文章,引出了一个关于"向前引用"的问题: public class InstanceInitTest { static { // { a = 6; System.ou ...
- python自定义函数可以向前引用不用声明
#有些编程语言不够"聪明",向这类向前引用的方式会导致报错,但Python足够"醒目",这段代码是正确的! def next(): print('我在n ...
- wpf staticresource 是不允许向前引用(forward reference)的
不允许向前引用(forward reference)在C/C++中中很常见,即在语法上,未定义变量.类之前,不能使用. 没想到wpf中的wpf staticresource也遵循这种规则.资源字典中, ...
- 向前引用 ? float VS long ? 这些知识你懂吗?
thinking in java 读书笔记(感悟): 作者:淮左白衣 : 写于 2018年4月2日18:14:15 目录 基本数据类型 float 和 long 谁更大 System.out.prin ...
- Java 9 揭秘(11. Java Shell)
Tips 做一个终身学习的人. 在本章节中,主要介绍以下内容: 什么是Java shell JShell工具和JShell API是什么 如何配置JShell工具 如何使用JShell工具对Java代 ...
- 深入理解Java虚拟机类加载机制
1.类加载时机 对于类加载的第一个阶段---加载,虚拟机没有强制的约束,但是对于初始化阶段,虚拟机强制规定有且只有以下的5中情况必须开始初始化,当然,加载.验证.准备阶段在初始化前就已经开始. ①使用 ...
- 《深入理解Java虚拟机》-----第7章 虚拟机类加载机制——Java高级开发必须懂的
代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言发展的一大步. 7.1 概述 上一章我们了解了Class文件存储格式的具体细节,在Class文件中描述的各种信息,最终都需要 ...
- 深入理解JVM(3)——类加载机制
1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...
随机推荐
- Tempdb--查看tempdb使用的脚本
GO /****** Object: StoredProcedure [dbo].[usp_GetTempDBUsedSpace] Script Date: 03/05/2014 13:24:42 * ...
- Centos 安装 erlang 环境
系统 Centos 6.5 64位 Erlang 18.3.4 安装依赖组件 yum install -y gcc gcc-g++ unixODBC unixODBC-devel wxBase wxG ...
- 转载WPF:创建你的第一个WPF项目
转载:http://www.cnblogs.com/pengjinyu/archive/2009/08/19/1549845.html
- 初学Ionic
官网 https://ionicframework.com/ 如连接所示,可跳转到该前端框架的官网,在这里提供了两种方式可供大家学习: Code with the CLI Design with lo ...
- .Net Mvc5Filter与权限认证扩展
WebForm 在做WebForm的时候,如果我们要实现某页面登陆后才能访问,这个非常容易实现 public partial class IndexForm : Page { protected vo ...
- Help Jimmy(动态规划)
点击打开链接 Help Jimmy Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 12168 Accepted: 402 ...
- Elasticsearch学习(4) spring boot整合Elasticsearch的聚合操作
之前已将spring boot原生方式介绍了,接下将结介绍的是Elasticsearch聚合操作.聚合操作一般来说是解决一下复杂的业务,比如mysql中的求和和分组,由于博主踩的坑比较多,所以博客可能 ...
- kvm虚拟化存储池配置
1.创建基于文件夹的存储池(目录) 2.定义存储池与其目录 # virsh pool-define-as vmdisk --type dir --target /data/vmfs 3.创建已定义的存 ...
- jmeter—解决响应乱码问题
问题: 当响应数据或响应页面没有设置编码时,jmeter会按照jmeter.properties文件中,sampleresult.default.encoding 设置的格式解析默认ISO-88 ...
- 3. STL编程三
1. 算法容器的使用: #include <iostream> #include <functional> #include <vector> #include & ...