基本介绍
代码块又被称为初始化块,是类的一部分,类似于方法,将逻辑语句封装在方法体中,包含于{}之中。但和方法不同,其没有方法名,没有返回,没有参数,只有方法体。而且不通过对象或类显式调用,而是在加载类时或创建对象时隐式的调用。
基本语法
[修饰符]{
代码
};
注意事项
1、修饰符可为static,也可为空,但不能为其他语句
2、代码块分两类:被static修饰的为静态代码块,无sattic修饰的为普通代码块/非静态代码块
3、句尾的“;”号可写可不写,但为了代码的规范以及可读性,建议加上“;”号
使用举例
我们以这段代码举例:
public class A {
public static void main(String[] args) {
b b1 = new b("1st");
b b2 = new b("2nd",5);
b b3 = new b("3rd",5,"3");
}
}
class b{
private String name;
private int num;
private String food;
public b(String name) {//单参构造器
this.name = name;
System.out.println("——————————————");
System.out.println("单参构造器被调用");
System.out.println("语句1");
System.out.println("语句2");
System.out.println("语句3");
}
public b(String name, int num) {//双参构造器
this.name = name;
this.num = num;
System.out.println("——————————————");
System.out.println("双参构造器被调用");
System.out.println("语句1");
System.out.println("语句2");
System.out.println("语句3");
}
public b(String name, int num, String food) {//三参构造器
this.name = name;
this.num = num;
this.food = food;
System.out.println("——————————————");
System.out.println("三参构造器被调用");
System.out.println("语句1");
System.out.println("语句2");
System.out.println("语句3");
}
}
执行结果:
——————————————
单参构造器被调用
语句1
语句2
语句3
——————————————
双参构造器被调用
语句1
语句2
语句3
——————————————
三参构造器被调用
语句1
语句2
语句3
在这段代码中,共有三个构造器,且每个构造器中均包含语句:
System.out.println("语句1");
System.out.println("语句2");
System.out.println("语句3");
这显得代码非常的冗余,此时我们便可以用到代码块对此以改进:
public class A {
public static void main(String[] args) {
b b1 = new b("1st");
b b2 = new b("2nd",5);
b b3 = new b("3rd",5,"3");
}
}
class b{
private String name;
private int num;
private String food;
{//定义代码块
System.out.println("语句1");
System.out.println("语句2");
System.out.println("语句3");
}
public b(String name) {//单参构造器
this.name = name;
System.out.println("——————————————");
System.out.println("单参构造器被调用");
}
public b(String name, int num) {//双参构造器
this.name = name;
this.num = num;
System.out.println("——————————————");
System.out.println("双参构造器被调用");
}
public b(String name, int num, String food) {//三参构造器
this.name = name;
this.num = num;
this.food = food;
System.out.println("——————————————");
System.out.println("三参构造器被调用");
}
}
执行结果:
语句1
语句2
语句3
——————————————
单参构造器被调用
语句1
语句2
语句3
——————————————
双参构造器被调用
语句1
语句2
语句3
——————————————
三参构造器被调用
此时我们注意到,虽输出语句相同,但执行顺序并不相同,系统,先执行了代码块中的代码,后执行构造函数中的代码此时我们可以得出结论:
1、每次调用构造器时,系统都会执行代码块
2、代码块先执行,构造函数后执行
静态代码块
static代码块也被称为静态代码块,作用就是对类进行初始化,它随着类的加载而被执行。与普通代码块不同的是,普通代码块每创建一个对象,都会被执行一次,而静态代码块只会在类加载时被执行一次。
静态代码块调用顺序
1、首次创建对象实例时(new),该类中静态代码块会被调用
public class go {
public static void main(String[] args) {
A a = new A(); //创建A类新对象a
A b = new A(); //创建A类新对象b
A c = new A(); //创建A类新对象c
}
}
class A{ //创建类
static { //创建静态代码块
System.out.println("静态代码块被调用");
}
}
执行结果:
静态代码块被调用
这篇代码创建了三个A类新对象,但静态代码块只被调用一次。由此可见,静态代码块虽然也和普通代码块一样,会在创建该类的新对象时被调用,但只会被调用一次
2、创建子类对象实例时,父类中的静态代码块也会被调用
public class go {
public static void main(String[] args) {
B b = new B(); //创建子类B类的新对象b
}
}
class A{//定义父类
static {//定义父类中的静态代码块
System.out.println("父类静态代码块被调用");
}
}
class B extends A{//定义子类
}
执行结果:
父类静态代码块被调用
3、调用类中的静态变量或静态方法时,本类以及父类中的静态代码块均会被调用
public class go {
public static void main(String[] args) {
//调用子类中的静态变量
System.out.println("调用子类中的静态变量num:"+B.num);
}
}
class A{ //父类A
static {//在父类中定义静态代码块
System.out.println("父类静态代码块被调用");
}
}
class B extends A{ //子类B
public static int num=0;//在子类中创建静态变量
}
执行结果:
父类静态代码块被调用
调用子类中的静态变量num:0
这种方法仅会调用本类及父类中的静态代码块,不会调用子类中的静态代码块,且同样只会调用一次静态代码块。
执行顺序
静态代码块与静态属性
两者之间的优先级相同,若有多个静态代码块或静态属性,则按照编写顺序来调用
public class go {
public static void main(String[] args) {
A a = new A();
}
}
class A{ //创建类
public static int num=getNum();
static { //创建静态代码块
System.out.println("静态代码块被调用");
}
public static int getNum(){
System.out.println("静态方法被调用");
return 10;
}
}
执行结果:
静态方法被调用
静态代码块被调用
因为 public static int num=getNum(); 写在前,且调用了getNum方法,所以“静态方法被调用”语句先输出,“静态代码块被调用”语句后输出,如果调换顺序,则输出顺序也会变:
public class go {
public static void main(String[] args) {
A a = new A();
}
}
class A{ //创建类
static { //创建静态代码块
System.out.println("静态代码块被调用");
}
public static int num=getNum();
public static int getNum(){
System.out.println("静态方法被调用");
return 10;
}
}
执行结果:
静态代码块被调用
静态方法被调用
普通代码块与普通属性
两者之间的优先级相同,若有多个普通代码块或普通属性,则按照编写顺序来调用,因其调用顺序与上文“静态代码块与静态属性”相同,在此不再举例。
与构造器的调用顺序
构造器会在最后才被调用,也就是说只有当上述方法全部执行结束后,构造器方法才会被调用。
与super的调用顺序
每个类都会包含一个super语句,且默认调用,但其调用顺序也在静态之后,也就是说,只有当代码中所有static都被调用后,才开始按照继承关系来执行super语句。
总结
各种不同模块之间的调用顺序:
1、父类静态属性=父类静态代码块(优先级相同,按书写顺序执行)
2、子类静态属性=子类静态代码块(优先级相同,按书写顺序执行)
3、父类super语句()>父类普通代码块 =父类普通属性(优先级相同,按书写顺序执行)
4、父类构造方法
5、子类super语句()>子类普通代码块 =子类普通属性(优先级相同,按书写顺序执行)
6、子类构造方法