目录
练习:分析有多个类并且存在继承关系以及存在有参构造器时代码段的执行顺序
代码块的作用
- 代码块用来初始化类和对象
- 代码块可以有修饰也可以没有修饰,当有修饰时,只能使用static关键字进行修饰
//这是一个没有修饰的代码块 class class1{ { System.out.println("这是一个没有修饰的代码块"); } }
//这是一个有修饰的代码块 class class1{ static{ System.out.println("这是一个有修饰的代码块"); } }
静态代码块和非静态代码块
静态代码块
- 静态代码块使用static关键字进行修饰
- 静态代码块的内部可以有输出语句
- 静态代码块在类加载时执行,并且只会执行一次(因为一个类只会加载一次)
- 静态代码块用于初始化类,但是初始化的是类的静态属性,类的非静态属性是无法在静态代码块中被初始化的
- 若是在一个类中存在多个静态代码块,那么执行时会按照这些静态代码块的定义顺序来执行
- 若是在静态代码块中存在调用,那么只能调用静态的属性和方法,不能调用非静态的属性和方法
非静态代码块
- 非静态代码块不使用static关键字进行修饰
- 非静态代码块的内部可以有输出语句
- 非静态代码块随着对象的创建而执行
- 每创建一个对象便会调用一次非静态代码块(因为非静态代码块是用于初始化对象的,因此,每次使用new关键字创建一个对象都会新增一个对象并使用非静态代码块对其初始化)
- 非静态代码块可以在创建对象时,对对象的属性进行初始化
- 若是在一个类中定义了多个非静态代码块,则这些非静态代码块会按照定义的先后顺序来执行
- 非静态代码块中,可以调用该类的静态属性、静态方法、非静态属性、非静态方法(因为静态的内容是随着类的加载而加载的,而非静态内容是在静态内容之后被加载的,因此非静态代码块调用已经存在的静态内容是完全没有问题的)
代码块的执行顺序
- 加载类的静态内容(先加载父类的再加载子类的)
- 加载父类的非静态内容(先加载普通成员,再加载构造器)
- 加载子类的非静态内容(先加载普通成员,再加载构造器)
总之,先加载静态的内容再加载非静态,先加载父类再加载子类
下面来总结一下代码块的执行顺序:
当没有其他继承关系时,也可以简化成这样的流程:
举个栗子1:没有继承关系时,代码块的执行顺序
现在有如下的代码块:
public class class4 {
//一个静态代码块
static {
System.out.println("class4静态代码块");
}
//一个非静态代码块
{
System.out.println("class4非静态代码块");
}
//主函数,程序的入口
public static void main(String[] args) {
}
}
这段代码的结构很简单,在class4类中只有一个静态代码块、一个非静态代码块以及一个内容为空的主函数。下面来具体分析这个代码段的执行过程:
若此时将这个类实例化一次
public class class4 {
//一个静态代码块
static {
System.out.println("class4静态代码块");
}
//一个非静态代码块
{
System.out.println("class4非静态代码块");
}
//主函数,程序的入口
public static void main(String[] args) {
new class4(); //实例化这个类
}
}
由于在实例化类时,会调用一次这个类的非静态代码块,因此,此时程序的输出的结果如下:
静态代码块在整个程序的生命周期中只会被执行一次,但是非静态代码块是创建一个对象就会被执行一次。
为了验证这一句,请看下面的代码段:
public class class4 {
//一个静态代码块
static {
System.out.println("class4静态代码块");
}
//一个非静态代码块
{
System.out.println("class4非静态代码块");
}
//主函数,程序的入口
public static void main(String[] args) {
System.out.println("\n下面创建了第一个对象");
new class4();
System.out.println("\n下面创建了第二个对象");
new class4();
}
}
此时,在主函数中创建了两个对象,若上面的结论成立,那么非静态代码块会被执行两次。
输出的结果如下:
可以看到,非静态代码块确实是被执行了两次,在每一次使用new关键字创建对象时都会被执行一次。
举个栗子2:有多个类并且存在继承关系时代码段的执行顺序
此时有如下的代码段:
public class class1 {
//一个静态代码块
static {
System.out.println("class1静态代码块");
}
//一个非静态代码块
{
System.out.println("class1非静态代码块");
}
}
public class class2 extends class1 {
//一个静态代码块
static {
System.out.println("class2静态代码块");
}
//一个非静态代码块
{
System.out.println("class2非静态代码块");
}
}
public class class3 extends class2 {
//一个静态代码块
static {
System.out.println("class3静态代码块");
}
//一个非静态代码块
{
System.out.println("class3非静态代码块");
}
}
public class class4 {
//一个静态代码块
static {
System.out.println("class4静态代码块");
}
//一个非静态代码块
{
System.out.println("class4非静态代码块");
}
}
public class Test {
static {
System.out.println("Test静态代码块");
}
{
System.out.println("Test非静态代码块");
}
public static void main(String[] args) {
System.out.println("Hello World");
}
static {
System.out.println("Test静态代码块1");
}
}
下面对代码块的执行顺序进行分析:
现在,对代码段稍作改动:
public class class1 {
//一个静态代码块
static {
System.out.println("class1静态代码块");
}
//一个非静态代码块
{
System.out.println("class1非静态代码块");
}
}
public class class2 extends class1 {
//一个静态代码块
static {
System.out.println("class2静态代码块");
}
//一个非静态代码块
{
System.out.println("class2非静态代码块");
}
}
public class class3 extends class2 {
//一个静态代码块
static {
System.out.println("class3静态代码块");
}
//一个非静态代码块
{
System.out.println("class3非静态代码块");
}
}
public class class4 {
//一个静态代码块
static {
System.out.println("class4静态代码块");
}
//一个非静态代码块
{
System.out.println("class4非静态代码块");
}
}
public class Test {
static {
System.out.println("Test静态代码块");
}
{
System.out.println("Test非静态代码块");
}
public static void main(String[] args) {
System.out.println("Hello World");
new class4();
}
static {
System.out.println("Test静态代码块1");
}
}
在主函数中创建了一个class4对象,此时再进行程序执行顺序的分析:
接下去再对代码段进行修改,在上面的基础上创建一个class1类:
public class class1 {
//一个静态代码块
static {
System.out.println("class1静态代码块");
}
//一个非静态代码块
{
System.out.println("class1非静态代码块");
}
}
public class class2 extends class1 {
//一个静态代码块
static {
System.out.println("class2静态代码块");
}
//一个非静态代码块
{
System.out.println("class2非静态代码块");
}
}
public class class3 extends class2 {
//一个静态代码块
static {
System.out.println("class3静态代码块");
}
//一个非静态代码块
{
System.out.println("class3非静态代码块");
}
}
public class class4 {
//一个静态代码块
static {
System.out.println("class4静态代码块");
}
//一个非静态代码块
{
System.out.println("class4非静态代码块");
}
}
public class Test {
static {
System.out.println("Test静态代码块");
}
{
System.out.println("Test非静态代码块");
}
public static void main(String[] args) {
System.out.println("Hello World");
new class4();
new class1();
}
static {
System.out.println("Test静态代码块1");
}
}
此时再进行程序执行顺序分析:
再对代码段进行修改,新建一个class2类对象,代码段如下:
public class class1 {
//一个静态代码块
static {
System.out.println("class1静态代码块");
}
//一个非静态代码块
{
System.out.println("class1非静态代码块");
}
}
public class class2 extends class1 {
//一个静态代码块
static {
System.out.println("class2静态代码块");
}
//一个非静态代码块
{
System.out.println("class2非静态代码块");
}
}
public class class3 extends class2 {
//一个静态代码块
static {
System.out.println("class3静态代码块");
}
//一个非静态代码块
{
System.out.println("class3非静态代码块");
}
}
public class class4 {
//一个静态代码块
static {
System.out.println("class4静态代码块");
}
//一个非静态代码块
{
System.out.println("class4非静态代码块");
}
}
public class Test {
static {
System.out.println("Test静态代码块");
}
{
System.out.println("Test非静态代码块");
}
public static void main(String[] args) {
System.out.println("Hello World");
new class4();
new class1();
new class2();
}
static {
System.out.println("Test静态代码块1");
}
}
再进行程序执行顺序分析:
最后,再创建一个class3类对象,代码段如下:
public class class1 {
//一个静态代码块
static {
System.out.println("class1静态代码块");
}
//一个非静态代码块
{
System.out.println("class1非静态代码块");
}
}
public class class2 extends class1 {
//一个静态代码块
static {
System.out.println("class2静态代码块");
}
//一个非静态代码块
{
System.out.println("class2非静态代码块");
}
}
public class class3 extends class2 {
//一个静态代码块
static {
System.out.println("class3静态代码块");
}
//一个非静态代码块
{
System.out.println("class3非静态代码块");
}
}
public class class4 {
//一个静态代码块
static {
System.out.println("class4静态代码块");
}
//一个非静态代码块
{
System.out.println("class4非静态代码块");
}
}
public class Test {
static {
System.out.println("Test静态代码块");
}
{
System.out.println("Test非静态代码块");
}
public static void main(String[] args) {
System.out.println("Hello World");
new class4();
new class1();
new class2();
new class3();
}
static {
System.out.println("Test静态代码块1");
}
}
此时的程序运行顺序分析如下:
练习:分析有多个类并且存在继承关系以及存在有参构造器时代码段的执行顺序
代码段如下:
public class Root {
static {
System.out.println("Root 的静态初始化块");
}
{
System.out.println("Root 的普通初始化块");
}
public Root() {
System.out.println("Root 的 无参构造器");
}
}
class Mid extends Root {
static {
System.out.println("Mid 的静态初始化块");
}
{
System.out.println("Mid 的普通初始化块");
}
public Mid() {
System.out.println("Mid 的 无参构造器");
}
public Mid(String msg) {
this();
System.out.println("Mid 的 有参构造器,参数为" + msg);
}
}
class Leaf extends Mid {
static {
System.out.println("Leaf 的静态初始化块");
}
{
System.out.println("Leaf 的普通初始化块");
}
public Leaf() {
super("herb");
System.out.println("Leaf 的 无参构造器");
}
}
class LeafTest {
public static void main(String[] args) {
new Leaf();
}
}
分析如下: