Java代码块
免责声明:java基础资料均来自于韩顺平老师的《循序渐进学Java零基础》教案,具体视频内容可以去B站观看,这些资料仅用于学习交流,不得转载用于商业活动
Java代码块
1.1 基本介绍
代码块又称为初始化块,属于类中的成员【即是类的一部分】,类似于方法,讲逻辑语句封装在方法中,通过{}包围起来
但和方法不同,没有方法名,没有返回,没有参数,只有方法提,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用
1.2 基本语法
[修饰符]{
代码
};
说明注意:
- 修饰符可选,要写的话,也只能写static
- 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块
- 逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
- ;可以写上,也可以省略
- 代码块相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作
- 场景:如果多个构造器中都有重复的语句,可以抽取到初始化代码块中,提高代码的重用性
1 public class CodeBlock { 2 public static void main(String[] args){ 3 Movie movie = new Movie("你好,李焕英"); 4 System.out.println("========"); 5 Movie movie2 = new Movie("流浪地球2",89.5,"吴京"); 6 7 } 8 } 9 10 class Movie{ 11 private String name; 12 private double price; 13 private String diretor; 14 15 //3个构造器-》重载 16 //(1)下面的三个构造器都有相同的语句 17 //(2)这样代码看起来比较冗余 18 //(3)这时我们可以把相同的语句,放入到一个代码块中,即可 19 //(4)这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容 20 //(5)代码块调用的顺序优先于构造器 21 { 22 System.out.println("电影屏幕打开..."); 23 System.out.println("广告开始..."); 24 System.out.println("电影正式开始..."); 25 } 26 27 public Movie(String name){ 28 System.out.println("Movie(String name)被调用"); 29 this.name = name; 30 } 31 32 public Movie(String name,double price){ 33 this.name = name; 34 this.price = price; 35 } 36 37 public Movie(String name,double price,String diretor){ 38 System.out.println("Movie(String name,double price,String diretor)被调用..."); 39 this.name = name; 40 this.price = price; 41 this.diretor = diretor; 42 } 43 }
1.3 代码块使用注意事项和细节讨论
- static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而运行,并且只会执行一次,如果是普通代码块,每创建一个对象,就执行
- 类什么时候被加载
- 创建对象实例时(new)
- 创建子类对象实例,父类也会被加载
- 使用类的静态成员时(静态属性,静态方法)
- 普通的代码块,在创建对象实例时,会被隐式的调用
- 被创建一次,就会调用一次
- 如果只是使用类的静态成员时,普通代码块并不会执行
小结:
- static代码块是类加载时,执行,只执行一次
- 普通代码块是在创建对象时调用的,创建一次,调用一次
- 类加载的3中情况,需要记住
public class CodeBlockDetail { public static void main(String[] args) { //类被加载的情况举例 //1.创建对象实例时(new) //AA aa = new AA(); //2.创建子类对象实例,父类也会被加载,而且,父类先被加载,子类后被加载 AA aa2 = new AA(); //3.使用类的静态成员时(静态属性,静态方法) System.out.println(Cat.n1); //static 代码块,是在类加载是,执行的,而且只会执行一次 DD dd = new DD(); DD dd1 =new DD(); //普通的代码块,在创建对象实例时,会被隐式的调用 //被创建一次,就会调用一次 //如果只是使用类的静态成员时,普通代码块并不会执行 System.out.println(DD.n1);//8888 静态模块一定会执行 } } class DD{ public static int n1 = 8888;//静态属性 //静态代码块 static{ System.out.println("DD的静态代码块1被执行..."); } //普通代码块,在new对象时,被调用,而且是每创建一个对象,就调用一次 //可以这样简单的理解 普通代码块是构造器的补充 { System.out.println("DD的普通代码块"); } } class Animal{ //静态代码块 static{ System.out.println("Animal的静态代码1被执行..."); } } class Cat extends Animal{ public static int n1 = 999;//静态属性 //静态代码块 static{ System.out.println("Cat的静态代码1被执行..."); } } class BB{ //静态代码块 static{ System.out.println("BB的静态代码1被执行"); } } class AA extends BB{ //静态代码块 static { System.out.println("AA的静态代码1被执行..."); } }
创建一个对象时,在已给类调用顺序是:(重点,难点)
- 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
- 调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
- 调用构造方法
1 public class CodeBlockDetail02 { 2 public static void main(String[] args) { 3 /* 4 A类的调用顺序: 5 1.A静态代码块01 6 2.getN1被调用 7 3.A普通代码块01 8 4.A()构造器被调用 9 5.getN2被调用... 10 */ 11 A a = new A(); 12 a.getN2(); 13 } 14 } 15 16 class A{ 17 //普通代码块 18 { 19 System.out.println("A的普通代码块01"); 20 } 21 //静态代码块 22 static{ 23 System.out.println("A静态代码块01"); 24 } 25 //静态属性的初始化 26 private static int n1=getN1(); 27 public static int getN1(){ 28 System.out.println("getN1被调用..."); 29 return 100; 30 } 31 //普通方法/非静态方法 32 public int getN2(){ 33 System.out.println("getN2被调用..."); 34 return 200; 35 } 36 //无参构造器 37 public A(){ 38 System.out.println("A()构造器被调用"); 39 } 40 }
构造器的最前面其实隐含了super()和调用普通代码块,静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此优先于构造器和普通代码块执行的
1 public class CodeBolckDetail03 { 2 public static void main(String[] args) { 3 /* 4 * (1)AAA的普通代码块 5 * (2)AAA()构造器被调用 6 * (3)BBB的普通代码块 7 * (4)BBB()构造器被调用 8 * */ 9 new BBB(); 10 } 11 } 12 13 class AAA{//父类Object 14 { 15 System.out.println("AAA的普通代码块"); 16 } 17 public AAA(){ 18 //(1)super(); 19 //(2)调用本类的普通代码块 20 System.out.println("AAA()构造器被调用..."); 21 } 22 } 23 24 class BBB extends AAA{ 25 { 26 System.out.println("BBB的普通代码块..."); 27 } 28 public BBB(){ 29 //(1)super(); 30 //(2)调用本类的普通代码块 31 System.out.println("BBB()构造器被调用..."); 32 } 33 }
我们看一下创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
- 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
- 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
- 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 父类的构造方法
- 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 子类的构造方法
静态代码块只能调用静态属性成员(静态属性和静态方法),普通代码块可以调用任意成员
public class CodeBlockDetail04 { public static void main(String[] args) { //说明 //(1)进行类的加载 //1.1 先加载父类A02 1.2 再加载B02 //(2)创建对象 //2.1 从子类的构造器开始 new B02();//对象 } } class A02{//父类 private static int n1 = getVal01(); static{ System.out.println("A02的一个静态代码块..."); } { System.out.println("A02的一个普通代码块.."); } public int n3=getVal02();//普通属性初始化 public static int getVal01(){ System.out.println("getVal01"); return 10; } public int getVal02(){ System.out.println("getVal02"); return 10; } public A02(){ //隐藏 //super(); //普通代码块和普通属性的初始化 System.out.println("A02的构造器"); } } 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); //m1();//错误 m2(); } { //普通代码块,可以使用任意成员 System.out.println(n1); System.out.println(n2);//ok m1(); m2(); } } class B02 extends A02{ private static int n3 =getVal03(); static{ System.out.println("B02的一个静态代码块.."); } public int n5=getVal04(); { System.out.println("B02的第一个普通代码块.."); } public static int getVal03(){ System.out.println("getVal03"); return 10; } public int getVal04(){ System.out.println("getVal04"); return 20; } public B02(){//构造器 //隐藏了 //super() //普通代码块和普通属性的初始化... System.out.println("B02的构造器"); } }