基本介绍:
概念:
代码块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法(可以看作只有方法体的方法),讲逻辑语句封装在方法体 中,通过{ }包围起来。
但和方法不同,没有方法名,没有返回值,没有参数,只有方法体,而且不用通过对象或者类显式调用,而是加载类时,或创建对象时隐式调用。
基本语法:
[修饰符]{
代码
};
细节:
2)代码块分为两类,使用static修饰的叫做静态代码块,没有static修饰的叫做普通代码块;
3)逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等);
代码块的好处:
1)相当于另外一种形式的构造器(普通代码块对构造器的补充机制),可以做初始化操作;
2)如果多个构造器存在重复语句,可以抽取到初始化块中,提高代码的重用性;
public class Test{
public static void main(String[] args){
Student tom = new Student("tom");
Student jack = new Student("jack",18);
Student smith = new Student("smith,22,10001);
}
}
class Student{
//私有属性
private String name;
private int age;
private long id;
//代码块
{
System.out.println("即将对学生点名!");
System.out.println("即将核对学生年龄!");
System.out.println("即将核对学生学号!");
}
//构造器
public Student(String name){
this.name = name;
System.out.println("调用了Student类的Student(String name)构造器");
}
public Student(String name , int age){
this.name = name;
this.age = age;
System.out.println("调用了Student类的Student(String name , int age)构造器");
}
public Student(String name , int age , long id){
this.name = name;
this.age = age;
this.id = id;
System.out.println("调用了Student类的Student(String name , int age , long id)构造器");
}
}
输出结果:
即将对学生点名!
即将核对学生年龄!
即将核对学生学号!
调用了Student类的Student(String name)构造器
即将对学生点名!
即将核对学生年龄!
即将核对学生学号!
调用了Student类的Student(String name , int age)构造器
即将对学生点名!
即将核对学生年龄!
即将核对学生学号!
调用了Student类的Student(String name , int age , long id)构造器
代码块使用注意事项和细节
1)static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,随着创建一个对象执行。
静态代码块随类加载而生,普通代码块随对象创建而生
2)类什么时候被加载[重要]:
①创建对象实例时(Student student = new Student(););
②创建子类对象实例,父类也会被加载;
③使用类的静态成员时(静态属性、静态方法)
package com.pero.codeblock;
/**
* 类加载的三种情况
* @version 1.0
* @author Pero
*/
public class Test01 {
public static void main(String[] args) {
//类被加载的情况举例
//1.创建对象实例时
//Person person = new Person();
//2.创建子类对象实例,父类也会被加载,父类先被加载,子类后被加载
//Student student = new Student();
//3.使用类的静态成员时(静态属性、静态方法)
System.out.println(Teacher.age);
}
}
class Person {
//静态代码块
static {
System.out.println("Person类的静态代码块1被执行");
};
}
class Student extends Person{
//静态代码块
static {
System.out.println("Student类的静态代码块1被执行");
};
}
class Teacher{
public static int age = 26;
//静态代码块
static {
System.out.println("Teacher类的静态代码块1被执行");
}
}
3)普通代码块,在创建对象实例时,会被隐式调用。被创建一次,就会调用一次。(可以将普通代码块看作构造器的补充,构造器被调用,他就会被调用)
package com.pero.codeblock;
/**
* 类加载的三种情况
* @version 1.0
* @author Pero
*/
public class Test01 {
public static void main(String[] args) {
//类被加载的情况举例
//1.创建对象实例时
//Person person = new Person();
//2.创建子类对象实例,父类也会被加载,父类先被加载,子类后被加载
//Student student = new Student();
//3.使用类的静态成员时(静态属性、静态方法)
//System.out.println(Teacher.age);
//类加载时,静态代码块只执行一次
//普通代码块在创建对象实例时,会被隐式调用,创建一次就调用一次
//如果只是使用类的静态成员时,普通代码块不会被执行
Teacher teacher1 = new Teacher();
Teacher teacher2 = new Teacher();
System.out.println(Teacher.age);
}
}
class Person {
//静态代码块
static {
System.out.println("Person类的静态代码块1被执行");
};
}
class Student extends Person{
//静态代码块
static {
System.out.println("Student类的静态代码块1被执行");
};
}
class Teacher{
public static int age = 26;
//静态代码块
static {
System.out.println("Teacher类的静态代码块1被执行");
}
//普通代码块
{
System.out.println("Teacher类的普通代码块1被执行");
};
}
4)创建一个对象时,在一个类调用顺序是:
①调用静态代码块和静态属性初始化(注意: 静态代码块和静态属性 初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,按照定义顺序(谁写前面先调用谁)调用);
②调用普通代码块和普通属性的初始化(注意:普通话代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,按照定义顺序调用);
③调用构造方法;
package com.pero.codeblock;
/**
* 创建一个对象时,在一个类调用顺序是:
* ①调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,
* 如果有多个静态代码块和多个静态变量初始化,按照定义顺序调用);
* ②调用普通代码块和普通属性的初始化(注意:普通话代码块和普通属性初始化调用的优先级一样,
* 如果有多个普通代码块和多个普通属性初始化,按照定义顺序调用);
* ③调用构造方法;
*
* @version 1.1
* @author Pero
*/
public class Test02 {
public static void main(String[] args) {
Model01 model01 = new Model01();
//(1)Model01静态属性被执行,getNumber1被调用
// (2)Model01的静态代码块1被执行
// (3)Model01普通属性被执行,getNumber2被调用
// (4)Model01的普通代码块1被执行
// (5)Model01构造器被执行
}
}
class Model01{
//普通属性的初始化
private int number2 = getNumber2();
//静态属性的初始化
private static int number1 = getNumber1();
//无参构造器
public Model01(){
System.out.println("Model01的构造器被执行");
}
//普通代码块
{
System.out.println("Model01的普通代码块1被执行");
};
//静态代码块
static {
System.out.println("Model01的静态代码块1被执行");
};
//静态方法
public static int getNumber1(){
System.out.println("静态方法getNumber1()方法被调用");
return 100;
}
//普通方法
public int getNumber2(){
System.out.println("普通方法getNumber2()方法被调用");
return 200;
}
}
5)构造器的前面隐含了super()和普通代码块的执行,静态相关的代码块和属性的初始化在类加载时就已经执行完毕,因此是优先于普通代码块和属性的初始化及构造器的执行;
package com.pero.codeblock;
/**
* 构造器的前面隐含了super()和普通代码块的执行,
* 静态相关的代码块和属性的初始化在类加载时就已经执行完毕,
* 因此是优先于普通代码块和属性的初始化及构造器的执行;
*
* @version 1.3
* @author Pero
*/
public class Test03 {
public static void main(String[] args) {
new T02();
// (1)T01的普通代码块被执行
// (2)T01构造器被调用
// (3)T02的普通代码块被调用
//(4)T02的构造器被调用
}
}
class T01{
//父类是Object类
{
System.out.println("T01的普通代码块被执行");
};
public T01(){
System.out.println("T01的无参构造器被调用");
}
}
class T02 extends T01{
//普通代码块
{
System.out.println("T02的普通代码块被执行");
};
public T02(){
//super();
//调用本类的普通代码块
System.out.println("T01的无参构造器被调用");
}
}
先加载后构造,加载静态,构造普通
父静态(按顺序) -> 子静态(按顺序) -> 父普通(按顺序) -> 父构造 -> 子普通(按顺序) -> 子构造
6)创建一个子类时(继承关系),父类与子类的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序;
①父类的静态代码块和静态属性(优先级一样,按定义顺序执行);
②子类的静态代码块和静态属性(优先级一样,按定义顺序执行);
③父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行);
④父类构造方法;
⑤子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行);
⑥子类的构造方法;
package com.pero.codeblock;
/**
* 创建一个子类时(继承关系),父类与子类的静态代码块,静态属性初始化,普通代码块,
* 普通属性初始化,构造方法的调用顺序;
* ①父类的静态代码块和静态属性(优先级一样,按定义顺序执行);
* ②子类的静态代码块和静态属性(优先级一样,按定义顺序执行);
* ③父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行);
* ④父类构造方法;
* ⑤子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行);
* ⑥子类的构造方法;
*/
public class Test04 {
public static void main(String[] args) {
//(1)进行类的加载
// 1.1先加载父类Animal类(执行静态代码块和属性);
// 1.2再加载子类Dog类(执行静态代码块和属性);
//(2)创建对象
// 从子类的构造器开始
// 2.1.1 super()
// 2.1.2 父类的普通代码块和普通属性
// 2.1.3 父类的构造方法
// 2.2.1 子类的普通代码块和普通属性
// 2.2.2 子类的构造方法
new Dog();
}
}
class Animal{
private static int a1 = getA1();//(1)
static {
System.out.println("Animal类的静态代码块1");//(2)
};
{
System.out.println("Animal类的普通代码块1");//(5)
};
public int a2 = getA2();//(6)
public static int getA1(){
System.out.println("Animal类的getA1静态方法");//(1)
return 100;
}
public int getA2(){
System.out.println("Animal类的getA2普通方法");//(6)
return 200;
}
public Animal(){
//super();
//普通代码块和属性的初始化
System.out.println("Animal类的无参构造器");//(7)
}
}
class Dog extends Animal{
private static int a3 = getA3();//(3)
static {
System.out.println("Dog类的静态代码块1");//(4)
};
public int a4 = getA4();//(8)
{
System.out.println("Dog类的普通代码块1");//(9)
}
public static int getA3(){
System.out.println("Dog类的getA3静态方法");//(3)
return 300;
}
public int getA4(){
System.out.println("Dog类的getA4普通方法");//(8)
return 400;
}
public Dog(){
//super();
//普通代码块和属性的初始化
System.out.println("Dog类的无参构造器");//(10)
}
}
7)静态代码块只能调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。
class Cat{
private int n1 = 100;
private static int n2 = 200;
private void m1(){
System.out.println("Cat类的普通方法m1()");
}
private static void m2(){
System.out.println("Cat类的静态方法m2()");
}
//静态代码块
static {
//System.out.println(n1);错误
System.out.println(n2);
//m1();错误
m2();
};
//普通代码块
{
System.out.println(n1);
System.out.println(n2);
m1();
m2();
};
}
练习
第一次Person.total加载类信息 执行上面的 静态属性和静态代码块 输出 in static block 然后输出100
第一次Person.total,无需加载类信息,直接输出100
输出1)静态成员sam初始化 2)static块被执行 3)sam1成员初始化 4)Test默认构造器函数被调用