目录
基本介绍
代码化块又称为初始化块,属于类中的成员[即 是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。 但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。
基本语法
修饰符;{
}
代码演示:
package idea.chapter10.codeblock_;
/**
* 演示代码块的基本使用
*/
public class codeBlock01 {
public static void main(String[] args) {
/*
基本介绍
代码化块又称为初始化块,属于类中的成员[即 是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。
但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。
*/
//怎么理解代码块是什么,我们看到,在Cat类中我们定义了三个构造器,这三个构造器中,都输出了两个相同的话
//我们在代码块的基本介绍中看到了,代码块是在加载类的时候,或者创建对象的时候隐式调用,
//定义了代码块之后,不管创建那个对象,都会先调用代码块中的内容
//因为实在加载类的时候调用的,所以我们只要创建了一个对象,那么就会导致,代买快中的内容被执行
Cat cat = new Cat();
}
}
//创建了一个Cat类
class Cat {
//定义了两个私有属性
private String name;
private int age;
//(1) 我们可以看到下面的三个构造器都有相同的语句
//(2) 这样代码看起来比较冗余
//(3) 这时我们可以把相同的语句,放入到一个代码块中,即可
//(4) 这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容
//(5) 代码块调用的顺序优先于构造器..
{
System.out.println("猫在叫");
System.out.println("猫在吃饭");
}
//无参构造器
public Cat() {
// System.out.println("猫在叫");
// System.out.println("猫在吃饭");
}
//带两个参数的构造器
public Cat(String name, int age) {
// System.out.println("猫在叫");
// System.out.println("猫在吃饭");
this.name = name;
this.age = age;
}
//带一个参数的构造器
public Cat(String name) {
// System.out.println("猫在叫");
// System.out.println("猫在吃饭");
this.name = name;
}
}
代码块注意事项
1)修饰符 可选,要写的话,也只能写static
2)代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块。
3)逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
4);号可以写上,也可以省略。
代码块的好处
1)相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作
2)场景:如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用
代码块注意事项和使用细节
1)static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象,就执行。
2)类什么时候被加载[重要背!]
1.创建对象实例时
2.创建子类对象实例,父类也会被加载
3.使用类的静态成员时(静态属性,静态方法)
3)普通的代码块,在创建对象实例时,会被隐式的调用。 被创建一次,就会调用一次。如果只是使用类的静态成员时,普通代码块并不会执行。
小结:
1.static代码块是类加载时,执行,只会执行一次
2.普通代码块是在创建对象时调用的,创建一次,调用一次
3.类加载的3种情况,需要记住。
代码演示:
注意
如果是继承的情况下,使用子类的静态属性,也会导致父类被加载
package idea.chapter10.codeblock_;
/**
* 演示代码块的细节1
*/
public class codeBlockDetail {
public static void main(String[] args) {
//1)static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象,就执行。
//2)类什么时候被加载[重要背!]
//1.创建对象实例时(new)
//AA aa = new AA();//这句话就会导致AA类的静态代码块被执行
//2.创建子类对象实例,父类也会被加载
//AA aa1 = new AA();//因为AA继承了BB所以,会导致BB类的静态代码块也会被执行,并且是先执行父类的静态代码块
//3.使用类的静态成员时(静态属性,静态方法) 使用子类的静态属性,也导致父类的加载
//System.out.println(Cat1.n1);//使用了Cat1类的静态属性,也会导致Cat1类中的静态代码块被执行,并且我们继承了Animal类,因此会先执行父类的静态代码块,在到子类的静态代码块
//static代码块,是在类加载时,执行的,而且只会执行一次.
//只会执行一次静态代码块中的内容,因为静态代码块是发生在类加载的时候的,类只会加载一次,所以静态代码块只会执行一次
//普通代码块是,每创建一个对象,就会调用一次
//DD dd = new DD();
//DD dd1 = new DD();
//3)普通的代码块,在创建对象实例时,会被隐式的调用。
// 被创建一次,就会调用一次。如果只是使用类的静态成员时,普通代码块并不会执行。
System.out.println(DD.n1);//因为我们只是,使用DD类的静态属性,所以会导致类被加载,因此一定会执行静态代码块中的内容,因为我们并没有创建对象,所以普通代码块中的内容不会被执行
//小结:
//1.static代码块是类加载时,执行,只会执行一次*
//2.普通代码块是在创建对象时调用的,创建一次,调用一次
//3.类加载的3种情况,需要记住。
}
}
class DD {
public static int n1 = 8888;//静态属性
//静态代码块
static {
System.out.println("DD 的静态代码块被执行...");//
}
//普通代码块, 在new 对象时,被调用,而且是每创建一个对象,就调用一次
//可以这样简单的,理解 普通代码块是构造器的补充
{
System.out.println("DD 的普通代码块...");
}
}
class Animal {
//静态代码块
static {
System.out.println("Animal 的静态代码块被执行...");//
}
}
class Cat1 extends Animal {
public static int n1 = 999;//静态属性
//静态代码块
static {
System.out.println("Cat 的静态代码块被执行...");//
}
}
class BB {
//静态代码块
static {
System.out.println("BB的静态代码块被执行");
}
}
class AA extends BB {
//静态代码块
static {
System.out.println("AA的静态代码块被执行");
}
}
4)创建一个对象时,在一个类 调用顺序是:(重点,难点):
1.调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)[举例说明]
2.调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
3.调用构造方法。
思路分析:
1.根据结论我们可以知道,在创建一个对象的时候,会先调用静态代码块和静态属性,但是因为静态代码块和静态属性优先级都一样,所以如果有多个静态代码块和静态属性,那么就按照定义的顺序的调用 所以因为在A类中,同时有一个静态代码块和静态属性,因为静态代码块定义在上面,所以优先执行静态代码块中的内容,因此会执行静态代码块中的内容(System.out.println("A 静态代码块01");) 然后去,执行初始化,静态属性,因为n1是通过getN1()方法进行赋值,所以会输出第二句话(System.out.println("getN1被调用...");) 2.在静态属性和静态初始化结束后,就会到我们的普通属性和普通代码块,他们的优先级也是一样的,所以,如果存在,多个普通属性和普通代码块,也是按照定义的顺序去调用, 所以会执行第三句话也就是普通代码块中的内容( System.out.println("A 普通代码块01");) 然后去初始化普通属性n2所以,因为n2是通过getN2()去赋值的 所以会输出第四句话(System.out.println("getN2被调用...");) 3.最后,在静态属性和静态代码块,普通属性和普通代码块结束之后,最后才是我们的构造器,所以第五句话输出的就是(System.out.println("A() 构造器被调用");)
代码演示:
package com.codeblock_;
/**
* 演示代码块的细节2
*/
public class codeBlockDetail02 {
public static void main(String[] args) {
A a = new A();// (1) A 静态代码块01 (2) getN1被调用...(3)A 普通代码块01(4)getN2被调用...(5)A() 构造器被调用
/*
思路分析
1.根据结论我们可以知道,在创建一个对象的时候,会先调用静态代码块和静态属性,但是因为静态代码块和静态属性优先级都一样,所以如果有多个静态代码块和静态属性,那么就按照定义的顺序的调用
所以因为在A类中,同时有一个静态代码块和静态属性,因为静态代码块定义在上面,所以优先执行静态代码块中的内容,因此会执行静态代码块中的内容(System.out.println("A 静态代码块01");)
然后去,执行初始化,静态属性,因为n1是通过getN1()方法进行赋值,所以会输出第二句话(System.out.println("getN1被调用...");)
2.在静态属性和静态初始化结束后,就会到我们的普通属性和普通代码块,他们的优先级也是一样的,所以,如果存在,多个普通属性和普通代码块,也是按照定义的顺序去调用,
所以会执行第三句话也就是普通代码块中的内容( System.out.println("A 普通代码块01");) 然后去初始化普通属性n2所以,因为n2是通过getN2()去赋值的
所以会输出第四句话(System.out.println("getN2被调用...");)
3.最后,在静态属性和静态代码块,普通属性和普通代码块结束之后,最后才是我们的构造器,所以第五句话输出的就是(System.out.println("A() 构造器被调用");)
*/
/*
结论:
4)创建一个对象时,在一个类 调用顺序是:(重点,难点):
1.调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)[举例说明]
2.调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
3.调用构造方法。
*/
}
}
class A {
{ //普通代码块
System.out.println("A 普通代码块01");//3
}
private int n2 = getN2();//普通属性的初始化
static { //静态代码块
System.out.println("A 静态代码块01");//1
}
//静态属性的初始化
private static int n1 = getN1();
public static int getN1() {
System.out.println("getN1被调用...");//2
return 100;
}
public int getN2() { //普通方法/非静态方法
System.out.println("getN2被调用...");//4
return 200;
}
//无参构造器
public A() {
System.out.println("A() 构造器被调用");//5
}
}
5)构造方法(构造器)的最前面其实隐含了 super 和 调用普通代码块,新写一个 类演示【截图+说明],静态相关的代码块,属性初始化,在类加载时,就执行完毕 ,因此是优先于 构造器和普通代码块执行的
思路分析:
1.通过结论我们可以知道,在构造器最后,最前面其实隐含了super()和调用普通代码块,所以我们在执行new BBB();这句话之后,就会去执行BBB类的无参构造器 因为BBB类的无参构造器中,隐含了super()和执行普通代码块,因为BBB继承了AAA所以会去执行AAA类的无参构造器,在AAA类的无参构造器中,也有隐藏的super和执行普通代码块 因为AAA类的父类是Object所以没有继续执行父类的构造器,因此会先输出AAA类中的普通代码块中的内容(System.out.println("AAA的普通代码块");), 然后会去执行AAA类的无参构造器中的内容,也就是第二句话(System.out.println("AAA() 构造器被调用....");), 在执行完父类的普通代码块后,和构造器之后,然后就会回到BBB类的无参构造器,所以会去执行BBB类的普通代码块,因为刚刚发生的内容都是在父类发生的,所以还要继续执行BBB类的普通代码块 也就是第三句话(System.out.println("BBB的普通代码块...");),最后输出BBB类构造器中的内容,也就是第四句话( System.out.println("BBB() 构造器被调用....");)
代码演示:
package com.codeblock_;
/**
* 演示代码块的细节3
*/
public class codeBlockDetail03 {
public static void main(String[] args) {
new BBB();//(1)AAA的普通代码块(2)AAA() 构造器被调用(3)BBB的普通代码块(4)BBB() 构造器被调用
/*
思路分析:
1.通过结论我们可以知道,在构造器最后,最前面其实隐含了super()和调用普通代码块,所以我们在执行new BBB();这句话之后,就会去执行BBB类的无参构造器
因为BBB类的无参构造器中,隐含了super()和执行普通代码块,因为BBB继承了AAA所以会去执行AAA类的无参构造器,在AAA类的无参构造器中,也有隐藏的super和执行普通代码块
因为AAA类的父类是Object所以没有继续执行父类的构造器,因此会先输出AAA类中的普通代码块中的内容(System.out.println("AAA的普通代码块");),
然后会去执行AAA类的无参构造器中的内容,也就是第二句话(System.out.println("AAA() 构造器被调用....");),
在执行完父类的普通代码块后,和构造器之后,然后就会回到BBB类的无参构造器,所以会去执行BBB类的普通代码块,因为刚刚发生的内容都是在父类发生的,所以还要继续执行BBB类的普通代码块
也就是第三句话(System.out.println("BBB的普通代码块...");),最后输出BBB类构造器中的内容,也就是第四句话( System.out.println("BBB() 构造器被调用....");)
*/
//结论
//5)构造方法(构造器)的最前面其实隐含了 super 和 调用普通代码块,静态相关的代码块,属性初始化,在类加载时,就执行完毕 ,因此是优先于 构造器和普通代码块执行的
}
}
class AAA { //父类Object
{
System.out.println("AAA的普通代码块");//1
}
public AAA() {
//(1)super()
//(2)调用本类的普通代码块
System.out.println("AAA() 构造器被调用....");//2
}
}
class BBB extends AAA {
{
System.out.println("BBB的普通代码块...");//3
}
public BBB() {
//(1)super()
//(2)调用本类的普通代码块
System.out.println("BBB() 构造器被调用....");//4
}
}
6)我们看一下创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下
①父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
②子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
③父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
④父类的构造方法
⑤子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
⑥子类的构造方法//面试题
7)静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调 用任意成员。
思路分析:
1.通过结论我们可以知道,在一个子类在继承了父类之后,再去创建子类对象的时候,会先去支持父类的静态代码块和静态属性,如果有多个静态代码块和静态属性,那么按照定义的顺序执行 所以会先去执行父类的静态属性,因为在父类的第一行,因为父类的n1属性是同过getVal01()方法赋值,所以会输出第一句话(System.out.println("getVal01");) , 然后再去执行父类的静态代码块,所以就会输出第二句话(System.out.println("A02的一个静态代码块..");) 2.然后再去执行子类的静态属性和静态代码块,因为子类的静态属性n3定义在第一行,所以会先执行n3属性,因为n3属性是通过getVal03()进行赋值,所以会输出第三局话(System.out.println("getVal03");) 然后再去执行子类的静态代码块,因此会输出第四句话(System.out.println("B02的一个静态代码块..");) 3.然后会去执行父类的普通代码块和普通属性的初始化,如果有多个普通属性和普通代码块他们的优先级一样,按照顺序去执行 所以会去父类的普通代码块就会输出第五句话(System.out.println("A02的第一个普通代码块..");) 然后再去初始化父类的普通属性,因为父类的普通属性是通过getVal02()赋值的,所以会输出第六句话( System.out.println("getVal02");) 4.然后就是执行父类的构造器,也就是会输出第7句话(System.out.println("A02的构造器");) 5.然后会去执行字类的普通代码块和普通属性的初始化,如果有多个普通属性和普通代码块他们的优先级一样,按照顺序去执行 所以会先去初始化子类的普通普通属性,因为子类的普通属性是通过getVal04()赋值的,所以会输出第八句话(System.out.println("getVal04");) 然后再去执行子类的普通代码块,就会输出第9句话也就是(System.out.println("B02的第一个普通代码块..");) 6.最后会去执行子类的无参构造器,就会输出第10句话(System.out.println("B02的构造器");)
代码演示:
package com.codeblock_;
/**
* 演示代码块的细节4
*/
public class codeBlockDetail04 {
public static void main(String[] args) {
//(1) 进行类的加载
//1.1 先加载 父类 A02 1.2 再加载 B02
//(2) 创建对象
//2.1 从子类的构造器开始
new B02();//对象
/*
思路分析:
1.通过结论我们可以知道,在一个子类在继承了父类之后,再去创建子类对象的时候,会先去支持父类的静态代码块和静态属性,如果有多个静态代码块和静态属性,那么按照定义的顺序执行
所以会先去执行父类的静态属性,因为在父类的第一行,因为父类的n1属性是同过getVal01()方法赋值,所以会输出第一句话(System.out.println("getVal01");) ,
然后再去执行父类的静态代码块,所以就会输出第二句话(System.out.println("A02的一个静态代码块..");)
2.然后再去执行子类的静态属性和静态代码块,因为子类的静态属性n3定义在第一行,所以会先执行n3属性,因为n3属性是通过getVal03()进行赋值,所以会输出第三局话(System.out.println("getVal03");)
然后再去执行子类的静态代码块,因此会输出第四句话(System.out.println("B02的一个静态代码块..");)
3.然后会去执行父类的普通代码块和普通属性的初始化,如果有多个普通属性和普通代码块他们的优先级一样,按照顺序去执行
所以会去父类的普通代码块就会输出第五句话(System.out.println("A02的第一个普通代码块..");)
然后再去初始化父类的普通属性,因为父类的普通属性是通过getVal02()赋值的,所以会输出第六句话( System.out.println("getVal02");)
4.然后就是执行父类的构造器,也就是会输出第7句话(System.out.println("A02的构造器");)
5.然后会去执行字类的普通代码块和普通属性的初始化,如果有多个普通属性和普通代码块他们的优先级一样,按照顺序去执行
所以会先去初始化子类的普通普通属性,因为子类的普通属性是通过getVal04()赋值的,所以会输出第八句话(System.out.println("getVal04");)
然后再去执行子类的普通代码块,就会输出第9句话也就是(System.out.println("B02的第一个普通代码块..");)
6.最后会去执行子类的无参构造器,就会输出第10句话(System.out.println("B02的构造器");)
*/
/*
结论
(6)我们看一下创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下
1.父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
2.子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
3.父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
4.父类的构造方法
5.子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
6.子类的构造方法
(7)静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调 用任意成员。
*/
}
}
class A02 { //父类
private static int n1 = getVal01();
static {
System.out.println("A02的一个静态代码块..");//(2)
}
{
System.out.println("A02的第一个普通代码块..");//(5)
}
public int n3 = getVal02();//普通属性的初始化
public static int getVal01() {
System.out.println("getVal01");//(1)
return 10;
}
public int getVal02() {
System.out.println("getVal02");//(6)
return 10;
}
public A02() {//构造器
//隐藏
//super()
//普通代码和普通属性的初始化......
System.out.println("A02的构造器");//(7)
}
}
class B02 extends A02 { //
private static int n3 = getVal03();
static {
System.out.println("B02的一个静态代码块..");//(4)
}
public int n5 = getVal04();
{
System.out.println("B02的第一个普通代码块..");//(9)
}
public static int getVal03() {
System.out.println("getVal03");//(3)
return 10;
}
public int getVal04() {
System.out.println("getVal04");//(8)
return 10;
}
//一定要慢慢的去品..
public B02() {//构造器
//隐藏了
//super()
//普通代码块和普通属性的初始化...
System.out.println("B02的构造器");//(10)
// TODO Auto-generated constructor stub
}
}
// (7)静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调 用任意成员。
class C02 {
private int n1 = 100;
private static int n2 = 200;
private void m1() {
}
private static void m2() {
}
static {
//静态代码块,只能调用静态成员
//System.out.println(n1);错误
System.out.println(n2);//ok
//m1();//错误
m2();
}
{
//普通代码块,可以使用任意成员
System.out.println(n1);
System.out.println(n2);//ok
m1();
m2();
}
}
代码块习题
第一题
思路分析:
1.因为使用类的静态属性会导致类的加载,所以在我们第一次使用Person.total的时候,就会先去执行静态代码块,在静态代码块中给total赋值了100 然后在输出(System.out.println("in static block!");)这句话,然后就是输出total的值,第二次在一次输出total的时候,不会再输出其他内容 只会输出total的值,因为类的加载只会发生一次 因此最后输出的内容就是 in static block! total = 100 total = 100 重点 2)类什么时候被加载 1.创建对象实例时 2.创建子类对象实例,父类也会被加载 3.使用类的静态成员时(静态属性,静态方法)
package com.codeblock_;
public class codeBlockExercise01 {
public static void main(String[] args) {
System.out.println("total = " + Person.total); //100
System.out.println("total = " + Person.total); //100
/*
思路分析:
1.因为使用类的静态属性会导致类的加载,所以在我们第一次使用Person.total的时候,就会先去执行静态代码块,在静态代码块中给total赋值了100
然后在输出(System.out.println("in static block!");)这句话,然后就是输出total的值,第二次在一次输出total的时候,不会再输出其他内容
只会输出total的值,因为类的加载只会发生一次
因此最后输出的内容就是
in static block!
total = 100
total = 100
重点
2)类什么时候被加载
1.创建对象实例时
2.创建子类对象实例,父类也会被加载
3.使用类的静态成员时(静态属性,静态方法)
*/
}
}
class Person {
public static int total;//静态变量
static {//静态代码块
total = 100;
System.out.println("in static block!");//(1)
}
}
第二题
思路分析:
1.我们创建了一个Test对象,就会导致类的加载,所以会先执行静态属性和静态代码块,因为Test类中有多个静态属性和静态代码块,因此按照顺序执行 所以会先执行 static Sample sam = new Sample("静态成员sam初始化 "); 这句话 ,这句话执行了后,就会去执行Sample类的有参构造器 会输出第一句话(System.out.println(静态成员sam初始化);) 2.然后会去执行静态代码块中的内容,会输出第二句话(System.out.println("static块执行");) 因为我们在执行静态代码块的时候,已经创建了Sample对象 所以此时再去判断 sam==null 不成立,所以就不会输出if语句中的内容 3.然后再去执行普通属性和普通代码块的初始化,所以会执行 Sample sam1 = new Sample("sam1成员初始化"); 这句话,会导致去调用父类的有参构造器 所以会输出第三局话(System.out.println(sam1成员初始化);) 4.最后一步,执行子类的构造器,输出第四句话(System.out.println("Test默认构造函数被调用");)
package com.codeblock_;
public class codeBlockExercise02 {
public static void main(String str[]) {
Test a = new Test();//无参构造器
//会先执行静态代码块和静态属性 然后在去执行非静态代码块和属性
//再去先去调用Test()类的无参构造器 无参构造器中会有一个隐藏的super()
/*
思路分析:
1.我们创建了一个Test对象,就会导致类的加载,所以会先执行静态属性和静态代码块,因为Test类中有多个静态属性和静态代码块,因此按照顺序执行
所以会先执行 static Sample sam = new Sample("静态成员sam初始化 "); 这句话 ,这句话执行了后,就会去执行Sample类的有参构造器
会输出第一句话(System.out.println(静态成员sam初始化);)
2.然后会去执行静态代码块中的内容,会输出第二句话(System.out.println("static块执行");) 因为我们在执行静态代码块的时候,已经创建了Sample对象
所以此时再去判断 sam==null 不成立,所以就不会输出if语句中的内容
3.然后再去执行普通属性和普通代码块的初始化,所以会执行 Sample sam1 = new Sample("sam1成员初始化"); 这句话,会导致去调用父类的有参构造器
所以会输出第三局话(System.out.println(sam1成员初始化);)
4.最后一步,执行子类的构造器,输出第四句话(System.out.println("Test默认构造函数被调用");)
*/
}
}
class Sample {
Sample(String s) {
System.out.println(s);
}
Sample() {
System.out.println("Sample默认构造函数被调用");//
}
}
class Test {
Sample sam1 = new Sample("sam1成员初始化");//3
static Sample sam = new Sample("静态成员sam初始化 ");//1
static {
System.out.println("static块执行");//2
if (sam == null) System.out.println("sam is null");
}
Test() {//构造器
System.out.println("Test默认构造函数被调用");//4
}
}