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 ...
随机推荐
- 团体程序设计天梯赛L1-020 帅到没朋友 2017-03-22 17:46 72人阅读 评论(0) 收藏
L1-020. 帅到没朋友 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 当芸芸众生忙着在朋友圈中发照片的时候,总有一些人因为 ...
- UVA 11235 Frequent values 线段树/RMQ
vjudge 上题目链接:UVA 11235 *******************************************************大白书上解释**************** ...
- underscore collections
1._.each(list, iterator, [context]):对集合中每一元素执行处理器方法. 如果传递了context参数,则把iterator绑定到context对象上.每次调用iter ...
- HTML解析器软件
HTML解析器软件 HTML文档解析器 HTMLParser HTML Parser 是一个对HTML进行分析的快速实时的解析器,最新的发行版本是1.6,另外2.0的开发版本已经两年没有进展了.示例代 ...
- 用.msi安装node时安装失败,出现rolling back action(转载)
转载地址:https://blog.csdn.net/qq_33295622/article/details/52956369在重装node时出现了上图所示情况,解决方法如下: 1.在官网下载稳定版本 ...
- Js 事件详解
1.事件流 1.1 事件流 描述的是在页面中接受事件的顺序 1.2 事件冒泡 由最具体的元素接收,然后逐级向上传播最不具体的元素的节点(文档) 1.3 事件捕获 最不具体的节点先接收事件,而最具体的节 ...
- 用MVC5+EF6+WebApi 做一个小功能(一)开场挖坑,在线答题系统
从哪开始说呢,这几年微软的技术一直在变,像是牟足了劲要累死所有的NET程序员,从WebForm到MVC到现在MPA.SPA .Razor单页,从net2.0一直走到现在.net4.6.2,后面还有一个 ...
- 使用apache-fileupload处理文件上传与上传多个文件 二(60)
一 使用apache-fileupload处理文件上传 框架:是指将用户经常处理的业务进行一个代码封装.让用户可以方便的调用. 目前文件上传的(框架)组件: Apache----fileupload ...
- Java按位取反运算符“~”的工作原理
说明:本文参考了文章<Java按位取反运算符“~”>,链接:https://blog.csdn.net/smilecall/article/details/4245447 补充:位运算符( ...
- BZOJ 4002--有意义的字符串(矩阵乘法)
4002: [JLOI2015]有意义的字符串 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 963 Solved: 416[Submit][Sta ...