我们已经知道,java有静态成员变量,有非静态成员变量,有静态代码块,有非静态代码块,有构造方法,有继承,那么虚拟机在创建一个类的时候,先做什么,后做什么,父类构造方法子类构造方法谁先执行?静态代码块非静态代码块谁先执行?我们写三个类来测试一下,一个父类,一个子类,一个执行类。
package com.dyz.test;
public class SuperTest{
//静态成员变量
public static String super_static = "父类静态变量";
//非静态成员变量
public String super_dynamic = "父类非静态变量";
//静态代码块
static{
System.out.println("父类静态代码块");
System.out.println("父类静态代码块中修改前的静态变量值:"+super_static);
super_static = "父类静态变量被父类静态代码块修改";
System.out.println("父类静态代码块中修改后的静态变量值:"+super_static);
}
//非静态代码块
{
System.out.println("父类非静态代码块");
System.out.println(super_dynamic);
super_dynamic = "父类非静态变量被父类非静态代码块修改";
System.out.println(super_dynamic);
}
//构造方法
public SuperTest(){
System.out.println("父类构造方法");
System.out.println("父类构造方法中的非静态变量值:"+super_dynamic);
super_dynamic = "父类非静态变量被父类构造方法修改";
System.out.println("父类构造方法中的非静态变量值:"+super_dynamic);
System.out.println("父类构造方法中修改前的静态变量值:"+super_static);
super_static = "父类静态变量被父类构造方法修改";
System.out.println("父类构造方法中修改后的静态变量值:"+super_static);
}
}
package com.dyz.test.son;
import com.dyz.test.SuperTest;
public class SonTest extends SuperTest{
public static String child_static = "子类静态变量";
public String child_dynamic = "子类非静态变量";
static{
System.out.println("子类静态代码块");
System.out.println("子类静态代码块中修改前的静态变量值:"+child_static);
child_static = "子类静态变量被子类静态代码块修改";
System.out.println("子类静态代码块中修改后的静态变量值:"+child_static);
}
{
System.out.println("子类非静态代码块");
System.out.println(child_dynamic);
child_dynamic = "子类非静态变量被子类非静态代码块修改";
System.out.println(child_dynamic);
}
public SonTest(){
System.out.println("子类构造方法");
System.out.println("子类构造方法中的非静态变量值:"+child_dynamic);
child_dynamic = "子类非静态变量被子类构造方法修改";
System.out.println("子类构造方法中的非静态变量值:"+child_dynamic);
System.out.println("子类构造方法中静态变量值:"+child_static);
child_static = "子类静态变量被子类静态代码块修改";
System.out.println("子类构造方法中静态变量值:"+child_static);
}
}
package com.dyz.test;
import com.dyz.test.son.*;
public class TestSonAndSuper{
public static String child_static = "静态变量";
public String child_dynamic = "非静态变量";
static{
System.out.println("静态代码块");
System.out.println("静态代码块中修改前的静态变量值:"+child_static);
child_static = "静态变量被子类静态代码块修改";
System.out.println("静态代码块中修改后的静态变量值:"+child_static);
}
{
System.out.println("非静态代码块");
System.out.println(child_dynamic);
child_dynamic = "非静态变量被非静态代码块修改";
System.out.println(child_dynamic);
}
public TestSonAndSuper(){
System.out.println("构造方法");
System.out.println("构造方法中的非静态变量值:"+child_dynamic);
child_dynamic = "非静态变量被构造方法修改";
System.out.println("构造方法中的非静态变量值:"+child_dynamic);
System.out.println("构造方法中静态变量值:"+child_static);
child_static = "静态变量被子类静态代码块修改";
System.out.println("构造方法中静态变量值:"+child_static);
}
public static void main(String[] args)throws InterruptedException{
System.out.println("开始执行main方法******");
int i = 0;
SonTest t = null;
while(i<10){
System.out.println(i);
i++;
Thread.sleep(1000);
}
t = new SonTest();
System.out.println("=============================");
t = new SonTest();
}
}
说下我们的设计思路:
1.静态变量和非静态变量定义时候直接初始化,然后在静态代码块和非静态代码块中看是否已经先执行了初始化,如果未初始化,理论输出应该是null;
2.执行类中也增加静态变量和静态代码块
3.main方法中增加一个延时器,设定时间10秒,然后创建子类对象。
OK我们来看执行结果
可以看到,执行类的静态代码块被执行了,即使我们没有实例化这个类,但是非静态块代码和构造方法没有被执行,因为我们没有创建执行类的对象。
我们从main方法和结果来看:
1.我们在main方法开始就打印了语句,但是静态块的语句却在更之前执行了
2.执行类的静态块在输出的时候,执行类的静态变量值已经有值了,也就是说静态变量的赋值在静态块之前执行。
3.我们声明了引用变量,但是声明语句过程中没有执行任何代码输出,此时子类和父类的静态块都没被执行
4.在延时器代码执行过程中,也没有任何其他代码被执行
5.父类的静态变量最先被赋值,然后执行了父类的静态块代码
6.子类的静态变量被赋值了,然后执行了子类的静态块代码
7.父类的非静态变量被赋值了,然后执行了父类的非静态代码块
8.父类的构造方法执行
9.子类的非静态变量被赋值了,然后执行了子类的非静态代码块
10. 子类的构造方法
11. 创建新的子类对象,也不会再执行静态变量的初始化和静态代码块了
从代码执行情况,我们现在可以判断创建一个新对象时各种初始化语句执行的先后顺序了:
1. 父类的静态变量初始化
2. 父类的静态代码块
3. 子类的静态变量初始化
4. 子类的静态代码块
5. 父类的非静态变量初始化
6. 父类的非静态代码块
7. 父类构造方法
8. 子类的非静态变量初始化
9. 子类的非静态代码块
10. 子类的构造方法
另外,我们还知道了:
1. 不管如何,静态变量初始化、静态代码块只会执行一次,而且一定是最先执行
2. 声明一个类型的引用变量,并不会执行这个类型的静态语句
3. 调用一个类的静态方法之前,会先执行执行静态变量赋值和静态代码块(从执行类main方法可以看出)
Java中的注释
//放在com.dyz.test包中
package com.dyz.test;
/**
* @author dyz
* @date 2018-05-25
* @version 1.0.0
* @description Example类,是一个公共类,不继承任何父类,
* 不实现任何接口,只用于举例描述各种注释
*/
public class Example{
//双斜杠注释可以放在代码上头
private String name;//也可以放在代码后面
//private String age; 如果放在代码前面,这行代码就会被注释掉,不生效
/*
这种注释可以跨行
*/
public void setName(String name){
this.name = name;
}
/**
* @author dyz
* @version 1.0.0
* @description 演示一下文档注释在代码中的使用
* @param 没有参数
* @returnType java.lang.String
*/
public String getName(){
/*
System.out.println("被注释起来的代码不会被执行");
*/
return this.name;
}
}
package com.dyz.test;import java.util.Scanner;public class HelloWorld{private String name;public static void main(String[] args){Scanner sc = new Scanner(System.in);System.out.println("Hello World!");sc.close();}}
试看上面这个类,全部挤在一起,空间倒是节省了,但是完全没有可读性,相信大家都不会喜欢。总之,我们写出来的代码要简洁美观、可读性强、逻辑性强。