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 ...
随机推荐
- intrinsicConditionQueue笔记
一, 使用conditionQueue需要注意的一些点: 一个conditionQueue被多种Predicate condition 使用是很正常的,所以当一个wait的线程被唤醒的时候,很有可能它 ...
- java中null转换成其它类型
对null进行强转会不会抛错.测试结果是,如果把null强转给对象,是不会抛异常的,因为本身对象是可以为null的.但是如果是基本类型,比如 int i = (Integer)obj的强转,其实内部会 ...
- Oracle EBS Export File Format
Profile Option Name Site Application Responsibility Server Server Org User Remark Export MIME type t ...
- [leetcode] 8. Maximum Depth of Binary Tree
可能是因为我是按难度顺序刷的原因,这个其实在之前的几道题里面已经写过了.题目如下: Given a binary tree, find its maximum depth. The maximum d ...
- 全面了解SQL
很多程序员认为SQL是一头难以驯服的野兽.它是为数不多的声明性语言之一,也因为这样,其展示了完全不同于其他的表现形式.命令式语言. 面向对象语言甚至函数式编程语言(虽然有些人觉得SQL 还是有些类似功 ...
- linux清理磁盘
https://blog.csdn.net/u012660464/article/details/78923011 有时候,服务突然挂了,再次启动却启动不了.一看,原来是磁盘空间被占满啦,那么,怎么清 ...
- 在Windows子系统(WSL)中配置开机启动服务
在WSL中跑了一些测试服务 比如 mysql nginx等,但关机后每次都要手动开启甚是吃力,本想着用rc.local来编辑开机启动 ,无奈不支持啊!先看看非WSL环境中是怎么实现的. 在 Ubunt ...
- c语言第一次作业--顺序、分支结构
1.1思维导图 1.2.1本周学习体会以及代码量学习体会 1.2.2学习体会 因为在暑假时候没有对c语言进行学习,没太关注一些学习资料,一些教学视频也没看,感觉对c语言是陌生的,刚开课的时候自 ...
- Oracle数据库exp和imp方式导数据
这里导入导出路径都在D盘下,默认文件名为:example.dmpexp方式导出数据相关参数项如下: 关键字 说明 默认USERID 用户名/口令FULL ...
- GO学习笔记 - 变量在定义时没有明确的初始化时会赋值为“零值 ”。
官方教程:https://tour.go-zh.org/basics/12 变量在定义时没有明确的初始化时会赋值为 零值 . 零值是: 数值类型为 0 , 布尔类型为 false , 字符串为 &qu ...