• Java面向对象(高级)-- 类的成员之四:代码块


    一、回顾

    (1)三条主线

    面向对象三条主线:

    ①类及类的内部成员(属性、方法、构造器;代码块、内部类)

    ②封装、继承、多态

    ③关键字

    (2)类中可以声明的结构及作用

    1.结构

    类中可以声明的结构:属性、方法、构造器;代码块(或初始化块)、内部类

    代码块:从长的样子来看的(就是封装了一下代码)

    初始化块:从它的作用的角度

    2.作用

    属性:基本的变量值

    方法:用来体现类的功能

    构造器:用来实例化创建对象

    代码块(或初始化块):用来初始化类或对象的信息(即初始化类或对象的成员变量)

    二、代码块

    (1)代码块的修饰与分类

    如果成员变量想要初始化的值不是一个硬编码的常量值,而是需要通过复杂的计算或读取文件、或读取运行环境信息等方式才能获取的一些值,该怎么办呢?

    此时,可以考虑代码块(或初始化块)。

    1. 代码块的修饰

    方法可以被修饰的有很多,比如权限修饰符、返回值类型…

    代码块可以被什么修饰呢?只能使用static进行修饰。(没有其他修饰了)

    2. 代码块的分类

    静态代码块:一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块(static block)

    //静态代码块
    static{
        
    }
    
    • 1
    • 2
    • 3
    • 4

    非静态代码块没有使用static修饰的,为非静态代码块。

    //非静态代码块
    {
        
    }
    
    • 1
    • 2
    • 3
    • 4

    3. 举例

    如下:

    package yuyi05;
    
    /**
     * ClassName: BlockTest
     * Package: yuyi05
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/11/19 0019 8:47
     */
    public class BlockTest {
    
    }
    
    class Person{
        //属性
        String name;
        int age;
    
        //方法
        public void eat(){
            System.out.println("民以食为天");
        }
    
        //构造器
        public Person(){
    
        }
    
    
        //非静态代码块
        {
            System.out.println("非静态代码块1");
        }
    
        //静态代码块
        static{
            System.out.println("静态代码块1");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    那么代码块什么时候执行呢?

    之前说过方法,方法有名字,什么时候调用什么时候就执行。方法又分为静态与非静态,这里的eat()是非静态,调用它的话就需要创建对象。

    首先造个对象,再通过对象去调用eat()方法。如下:

    public class BlockTest {
        public static void main(String[] args) {
            Person p1=new Person();
            p1.eat();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行就可以输出结果了:

    image.png

    可以看到,除了调用了eat()方法之外,它将静态代码块和非静态代码块都执行了。

    代码块都没有名字了,它就不会像方法一样调它的时候执行。既然没有名字,主动去调用吧,都不知道该怎么调。

    所以这样的结构,不是我们主动调用的。它是在某个特定的场景下自动执行的。

    那么静态代码块和非静态代码块在什么场景下执行呢?请看后面👇

    (2) 静态代码块

    如果想要为静态变量初始化,可以直接在静态变量的声明后面直接赋值,也可以使用静态代码块。

    1. 语法格式

    在代码块的前面加static,就是静态代码块。

    【修饰符】 class{
    	static{
            静态代码块
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 静态代码块的特点

    1. 可以有输出语句。
    2. 可以对类的属性、类的声明进行初始化操作。
    3. 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
    4. 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
    5. 静态代码块的执行要先于非静态代码块。
    6. 静态代码块随着类的加载而执行(它没有名字,就不能显示地调用它)。
    7. 由于类的加载只会执行一次,进而静态代码块的执行,也只会执行一次

    (3)非静态代码块

    1. 语法格式

    【修饰符】 class{
        {
            非静态代码块
        }
        【修饰符】 构造器名(){
        	// 实例初始化代码
        }
        【修饰符】 构造器名(参数列表){
            // 实例初始化代码
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2. 非静态代码块的作用

    构造器一样,也是用于实例变量的初始化等操作

    3. 非静态代码块的意义

    如果多个重载的构造器有公共代码,并且这些代码都是先于构造器其他代码执行的,那么可以将这部分代码抽取到非静态代码块中,减少冗余代码。

    4. 非静态代码块的执行特点

    1. 可以有输出语句。
    2. 可以对类的属性、类的声明进行初始化操作。
    3. 除了调用非静态的结构外,还可以调用静态的变量或方法。
    4. 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
    5. 每次创建对象的时候,都会执行一次。且先于构造器执行。

    (4)举例

    1. 举例1

    public class BlockTest {
        public static void main(String[] args) {
            //在创建对象之前,通过类调用静态属性
            System.out.println(Person.info);    //调用静态属性,既然调用了,那么一定会加载Person类
    
            //在加载类的时候,静态代码块就会被执行
        }
    }
    
    class Person{
    
        static String info="我是一个人"; //静态属性
    
        //构造器
        public Person(){
    
        }
    
        //非静态代码块
        {
            System.out.println("非静态代码块1");
        }
    
        //静态代码块
        static{
            System.out.println("静态代码块1");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    输出结果:

    image.png

    在main方法中调用静态属性,既然调用了,那么一定会加载Person类。

    而在加载类的时候,静态代码块就会被执行。所以输出结果有静态代码块中的内容。

    静态代码块随着类的加载而执行。

    2. 举例2

    System.out.println(Person.info);

    虽然此语句执行了两次,但是类只加载一次,静态代码块也只加载一次。(类不加载了,静态代码块自然也不会去执行)

    public class BlockTest {
        public static void main(String[] args) {
            //在创建对象之前,通过类调用静态属性
            System.out.println(Person.info);    //调用静态属性,既然调用了,那么一定会加载Person类
        	System.out.println(Person.info); 	//虽然此语句执行了两次,但是类只加载一次,静态代码块也只加载一次
        }
    }
    
    class Person{
    
        static String info="我是一个人"; //静态属性
    
        //构造器
        public Person(){
    
        }
    
        //非静态代码块
        {
            System.out.println("非静态代码块1");
        }
    
        //静态代码块
        static{
            System.out.println("静态代码块1");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    输出结果:

    image.png

    可以看到,“静态代码块1”只输出了一句。

    类的加载只会执行一次,进而静态代码块也只会调用一次

    3. 举例3

    在刚才的演示中,可以发现非静态代码块是没有执行的,因为它是非静态的,与类的加载没啥关系,只会跟**对象的加载(创建)**有关。

    比如创建了一个当前类的对象p1,既然对象创建了,那么非静态的变量就会在堆空间中被分配了,非静态的方法也就可以通过对象来调用了,同样,非静态代码块也会执行了。

    比如:

    public class BlockTest {
        public static void main(String[] args) {
            //在创建对象之前,通过类调用静态属性
            System.out.println(Person.info);    //调用静态属性,既然调用了,那么一定会加载Person类
            System.out.println(Person.info);
    
            Person p1=new Person();
            //p1.eat();
        }
    }
    
    class Person{
        //属性
        String name;
        int age;
    
        static String info="我是一个人"; //静态属性
    
        //方法
        public void eat(){
            System.out.println("民以食为天");
        }
    
        //构造器
        public Person(){
    
        }
    
    
        //非静态代码块
        {
            System.out.println("非静态代码块1");
        }
    
        //静态代码块
        static{
            System.out.println("静态代码块1");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    输出结果:

    image.png

    非静态代码块随着对象的创建而执行。

    4. 举例4

    若是创建类的多个对象会怎么样呢?

    比如此时又创建了一个对象p2:

    package yuyi05;
    
    public class BlockTest {
        public static void main(String[] args) {
            //在创建对象之前,通过类调用静态属性
            System.out.println(Person.info);    //调用静态属性,既然调用了,那么一定会加载Person类
            System.out.println(Person.info);
    
            Person p1=new Person();
            Person p2=new Person();
            //p1.eat();
        }
    }
    
    class Person{
        //属性
        String name;
        int age;
    
        static String info="我是一个人"; //静态属性
    
        //方法
        public void eat(){
            System.out.println("民以食为天");
        }
    
        //构造器
        public Person(){
    
        }
    
    
        //非静态代码块
        {
            System.out.println("非静态代码块1");
        }
    
        //静态代码块
        static{
            System.out.println("静态代码块1");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    输出结果:

    image.png

    每创建当前类的一个实例,就会执行一次非静态代码块

    5. 举例5

    静态代码块用来初始化类的信息,非静态代码块用来初始化对象的信息

    那这些信息指的是什么?代码块里面可以写什么呢?

    代码块的大括号就相当于方法的大括号,方法里面可以调用当前类中的成员变量、方法、自己写的输出语句…

    代码块里面也是同样的,它里面也可以做这些事儿。

    比如定义了静态属性info,那么在静态代码块中也可以调用它。如下:

    //静态代码块
    static{
        System.out.println("静态代码块1");
        System.out.println("修改前的info= "+info);  //打印info
        info="我是超人";//修改info (相当于对info初始化)
        System.out.println("修改后的info= "+info);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    同样,对于非静态代码块,每造一个对象它就会执行一次,比如在里面将age赋值为1。如下:

    //非静态代码块
    {
        System.out.println("非静态代码块1");
        age=1;  //修改age的值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    若此时通过对象调用age:System.out.println(p1.age); ,它的值是多少呢?(空参构造器没有给它赋值,也没有显示赋值)

    整体代码:

    package yuyi05;
    
    public class BlockTest {
        public static void main(String[] args) {
            //在创建对象之前,通过类调用静态属性
            System.out.println(Person.info);    //调用静态属性,既然调用了,那么一定会加载Person类
            System.out.println(Person.info);
    
            Person p1=new Person();
            Person p2=new Person();
    
            System.out.println(p1.age); //输出age
        }
    }
    
    class Person{
        //属性
        String name;
        int age;
    
        static String info="我是一个人"; //静态属性
    
        //方法
        public void eat(){
            System.out.println("民以食为天");
        }
    
        //构造器
        public Person(){
    
        }
    
    
        //非静态代码块
        {
            System.out.println("非静态代码块1");
            age=1;  //修改age的值
        }
    
        //静态代码块
        static{
            System.out.println("静态代码块1");
            System.out.println("修改前的info= "+info);  //打印info
            info="我是超人";//修改info (相当于对info初始化)
            System.out.println("修改后的info= "+info);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    输出结果:

    image.png

    执行结果是1,因为在创建对象的时候,非静态代码块执行了,执行的时候就把当前正在创建的对象的属性赋值了。(初始化对象的信息

    无论是静态代码块还是非静态代码块,内部都可以进行声明变量、调用属性或方法、编写输出语句等操作。

    对应的执行代码:


    image.png


    image.png


    image.png


    image.png

    先执行静态代码块,后执行非静态代码块。

    因为类先加载(类加载的时候静态代码块执行,且执行一次),然后构造器就加载了,通过构造器才能造对象(每造一个对象就执行一次非静态代码块)。

    6. 举例6

    在一个类中,可以写多个静态代码块和非静态代码块吗?可以的。

    比如:

    package yuyi05;
    
    public class BlockTest {
        public static void main(String[] args) {
            //在创建对象之前,通过类调用静态属性
            System.out.println(Person.info);    //调用静态属性,既然调用了,那么一定会加载Person类
            System.out.println(Person.info);
    
            Person p1=new Person();
            Person p2=new Person();
    
            System.out.println(p1.age); //输出age
            //p1.eat();
        }
    }
    
    class Person{
        //属性
        String name;
        int age;
    
        static String info="我是一个人"; //静态属性
    
        //方法
        public void eat(){
            System.out.println("民以食为天");
        }
    
        //构造器
        public Person(){
    
        }
    
    
        //非静态代码块
        {
            System.out.println("非静态代码块1");
            age=1;  //修改age的值
        }
    
        {
            System.out.println("非静态代码块2");
        }
    
        //静态代码块
        static{
            System.out.println("静态代码块1");
        }
        static{
            System.out.println("静态代码块2");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    输出结果:

    image.png

    在一个类中,可以写多个静态代码块和非静态代码块。

    7. 举例7

    在静态代码块和非静态代码块中的代码执行顺序取决于写的顺序。

    比如:

    public class BlockTest {
        public static void main(String[] args) {
            //在创建对象之前,通过类调用静态属性
            System.out.println(Person.info);    //调用静态属性,既然调用了,那么一定会加载Person类
            System.out.println(Person.info);
    
            Person p1=new Person();
            Person p2=new Person();
    
            //System.out.println(p1.age); //输出age
            //p1.eat();
        }
    }
    
    class Person{
        //属性
        String name;
        int age;
    
        static String info="我是一个人"; //静态属性
    
        //方法
        public void eat(){
            System.out.println("民以食为天");
        }
    
        //构造器
        public Person(){
    
        }
    
    
        //非静态代码块
        {
            System.out.println("非静态代码块2");
        }
    
        {
            System.out.println("非静态代码块1");
            age=1;  //修改age的值
        }
    
    
    
        //静态代码块
        static{
            System.out.println("静态代码块2");
        }
    
        static{
            System.out.println("静态代码块1");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    输出结果:

    image.png

    在一个类中,若是编写了很多静态代码块和非静态代码块,它们的执行顺序就是声明的顺序。

    在实际开发中,不会去声明多个的。既然是按照先后顺序执行的,那跟写在一个里面没啥区别。(如果写了好几个,生成的字节码文件也会帮我们合并起来)。所以写一个就好,没必要写多个。

    8. 举例8

    静态代码块内部只能调用静态的结构(即静态的属性、方法),不能调用非静态的结构(即非静态的属性、方法)。

    //静态代码块
    static{
        System.out.println("静态代码块2");
        System.out.println("info= "+info);  //静态代码块中可以调用静态属性或方法
    
        //静态代码块中不可以调用非静态属性或方法
        //System.out.println("age= "+age);
        //eat();
    
    }
    
    static{
        System.out.println("静态代码块1");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    非静态代码块内部可以调用静态的结构(即静态的属性、方法),也可以调用非静态的结构(即非静态的属性、方法)。

    //非静态代码块
    {
        System.out.println("非静态代码块2");
    }
    
    {
        System.out.println("非静态代码块1");
        age=1;  //修改age的值 ,非静态代码块中可以调用非静态的属性或方法
    
        //非静态代码块中可以调用静态属性或方法(提前就已经加载过了)
        System.out.println("info= "+info);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    整体代码:

    package yuyi05;
    
    /**
     * ClassName: BlockTest
     * Package: yuyi05
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/11/19 0019 8:47
     */
    public class BlockTest {
        public static void main(String[] args) {
            //在创建对象之前,通过类调用静态属性
            System.out.println(Person.info);    //调用静态属性,既然调用了,那么一定会加载Person类
            System.out.println(Person.info);
    
            Person p1=new Person();
            Person p2=new Person();
    
            //System.out.println(p1.age); //输出age
            //p1.eat();
        }
    }
    
    class Person{
        //属性
        String name;
        int age;
    
        static String info="我是一个人"; //静态属性
    
        //方法
        public void eat(){
            System.out.println("民以食为天");
        }
    
        //构造器
        public Person(){
    
        }
    
    
        //非静态代码块
        {
            System.out.println("非静态代码块2");
        }
    
        {
            System.out.println("非静态代码块1");
            age=1;  //修改age的值 ,非静态代码块中可以调用非静态的属性或方法
    
            //非静态代码块中可以调用静态属性或方法(提前就已经加载过了)
            System.out.println("info= "+info);
    
        }
    
    
    
        //静态代码块
        static{
            System.out.println("静态代码块2");
            System.out.println("info= "+info);  //静态代码块中可以调用静态属性或方法
    
            //静态代码块中不可以调用非静态属性或方法
            //System.out.println("age= "+age);
            //eat();
    
        }
    
        static{
            System.out.println("静态代码块1");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    输出结果:

    image.png

    有类不一定有对象,有对象一定有类

    (5)重点总结

    1. 静态代码块

    • 随着类的加载而执行(它没有名字,就不能显示地调用它)。
    • 由于类的加载只会执行一次,进而静态代码块的执行,也只会执行一次
    • 作用:用来初始化类的信息
    • 内部可以声明变量、调用属性或方法、编写输出语句等操作。
    • 静态代码块的执行要先于非静态代码块的执行
    • 如果声明有多个静态代码块,则按照声明的先后顺序执行。
    • 静态代码块内部只能调用静态的结构(即静态的属性、方法),不能调用非静态的结构(即非静态的属性、方法)

    2. 非静态代码块

    • 随着对象的创建而执行
    • 每创建当前类的一个实例,就会执行一次非静态代码块
    • 作用:用来初始化对象的信息
    • 内部可以声明变量、调用属性或方法、编写输出语句等操作。
    • 如果声明有多个非静态代码块,则按照声明的先后顺序执行。
    • 非静态代码块内部可以调用静态的结构(即静态的属性、方法),也可以调用非静态的结构(即非静态的属性、方法)

    一般在开发中使用的时候,静态代码块初始化的时候,把静态的属性做一个赋值;非静态代码块初始化的时候,可以对非静态的属性做一些赋值。

    有类就有静态代码块,不创造对象构造器也不会执行;继承的时候普通代码块和构造器的区别就体现了。

    三、练习

    (1)练习

    🌋题目描述

    (1)声明User类,

    • 包含属性:username(String类型),password(String类型),registrationTime(long类型),私有化
    • 包含get/set方法,其中registrationTime没有set方法
    • 包含无参构造,
      • 输出“新用户注册”,
      • registrationTime赋值为当前系统时间,
      • username就默认为当前系统时间值,
      • password默认为“123456”
    • 包含有参构造(String username, String password),
      • 输出“新用户注册”,
      • registrationTime赋值为当前系统时间,
      • username和password由参数赋值
    • 包含public String getInfo()方法,返回:“用户名:xx,密码:xx,注册时间:xx”

    (2)编写测试类,测试类main方法的代码如下:

        public static void main(String[] args) {
            User u1 = new User();
            System.out.println(u1.getInfo());
    
            User u2 = new User("song","8888");
            System.out.println(u2.getInfo());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    💨代码

    【User.java】

    package yuyi05;
    
    /**
     * ClassName: User
     * Package: yuyi05
     * Description:
     *  - 包含属性:userName(String类型),password(String类型),registrationTime(long类型),私有化
     *
     * - 包含get/set方法,其中registrationTime没有set方法
     *
     * - 包含无参构造,
     *   - 输出“新用户注册”,
     *   - registrationTime赋值为当前系统时间,
     *   - userName就默认为当前系统时间值,
     *   - password默认为“123456”
     *
     * - 包含有参构造(String userName, String password),
     *   - 输出“新用户注册”,
     *   - registrationTime赋值为当前系统时间,
     *   - username和password由参数赋值
     *
     * - 包含public String getInfo()方法,返回:“用户名:xx,密码:xx,注册时间:xx”
     * @Author 雨翼轻尘
     * @Create 2023/11/19 0019 14:45
     */
    public class User {
        //属性
        private String username;
        private String password;
        private long registrationTime;  //注册时间
    
        //方法
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public long getRegistrationTime() {
            return registrationTime;
        }
    
        public String getInfo(){
            return "用户名:"+username+",密码:"+password+",注册时间"+registrationTime;
        }
    
        //构造器
        public User(){
            System.out.println("新用户注册");
            registrationTime=System.currentTimeMillis();    //获取系统当前时间 (距离1970-1-1  00:00:00 的毫秒数,得到的是long类型的值)
            username=System.currentTimeMillis()+""; //字符串连接操作中隐式类型转换 (不是自动类型提升,自动类型 提升只针对于基本数据类型)
            password="123456";
        }
    
        public User(String username,String password){
            System.out.println("新用户注册");
            registrationTime=System.currentTimeMillis();    //获取系统当前时间
            this.username=username;
            this.password=password;
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    【UserTest.java】

    package yuyi05;
    
    /**
     * ClassName: UserTest
     * Package: yuyi05
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/11/19 0019 15:13
     */
    public class UserTest {
        public static void main(String[] args) {
            User u1=new User();
            System.out.println(u1.getInfo());
    
            User u2=new User("Tom","5664321");
            System.out.println(u2.getInfo());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    输出结果:

    image.png


    这也没有用到代码块啊?

    现在我们写一个User1类,将刚才的User代码拿过来。(记得更改构造器的名字为类名)

    package yuyi05;
    
    /**
     * ClassName: User1
     * Package: yuyi05
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/11/19 0019 15:19
     */
    public class User1 {
        private String username;
        private String password;
        private long registrationTime;  //注册时间
    
        //方法
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public long getRegistrationTime() {
            return registrationTime;
        }
    
        public String getInfo(){
            return "用户名:"+username+",密码:"+password+",注册时间"+registrationTime;
        }
    
        //构造器
        public User1(){
            System.out.println("新用户注册");
            registrationTime=System.currentTimeMillis();    //获取系统当前时间 (距离1970-1-1  00:00:00 的毫秒数,得到的是long类型的值)
            username=System.currentTimeMillis()+""; //字符串连接操作中隐式类型转换 (不是自动类型提升,自动类型 提升只针对于基本数据类型)
            password="123456";
        }
    
        public User1(String username,String password){
            System.out.println("新用户注册");
            registrationTime=System.currentTimeMillis();    //获取系统当前时间
            this.username=username;
            this.password=password;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    现在没有涉及到静态的性质,所以就用不着静态代码块了。

    这个类在加载的时候需要干点什么么?此时没啥可干的。

    非静态代码块可以稍微体会一下,可以对当前类中的属性做一些赋值操作。(每创建一个对象它就会执行一次,和用哪个构造器无关)

    在new对象的时候,代码块就执行了,跟用哪个构造器无关。

    此时可以看到,两个构造器有相同的代码,比如前两行:

    image.png

    既然有相同的代码,意味着这两行都要执行,既然都要被执行,那在调用构造器的时候,代码块也会执行,不妨将这两行的逻辑写入代码块中。

    //非静态代码块
    {
        System.out.println("新用户注册");
        registrationTime=System.currentTimeMillis();    //获取系统当前时间 (距离1970-1-1  00:00:00 的毫秒数,得到的是long类型的值)
    }
    
    //构造器
    public User1(){
        username=System.currentTimeMillis()+""; //字符串连接操作中隐式类型转换 (不是自动类型提升,自动类型 提升只针对于基本数据类型)
        password="123456";
    }
    
    public User1(String username,String password){
        this.username=username;
        this.password=password;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    这里的变化如下:

    image.png

    当我们通过User1()构造器造对象的时候,非静态代码块中的内容一定会执行。

    现在整体的代码如下:

    【User1.java】

    package yuyi05;
    
    /**
     * ClassName: User1
     * Package: yuyi05
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/11/19 0019 15:19
     */
    public class User1 {
        private String username;
        private String password;
        private long registrationTime;  //注册时间
    
        //方法
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public long getRegistrationTime() {
            return registrationTime;
        }
    
        public String getInfo(){
            return "用户名:"+username+",密码:"+password+",注册时间"+registrationTime;
        }
    
        //非静态代码块
        {
            System.out.println("新用户注册");
            registrationTime=System.currentTimeMillis();    //获取系统当前时间 (距离1970-1-1  00:00:00 的毫秒数,得到的是long类型的值)
        }
    
        //构造器
        public User1(){
            username=System.currentTimeMillis()+""; //字符串连接操作中隐式类型转换 (不是自动类型提升,自动类型 提升只针对于基本数据类型)
            password="123456";
        }
    
        public User1(String username,String password){
            this.username=username;
            this.password=password;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    测试类【UserTest.java】

    package yuyi05;
    
    /**
     * ClassName: UserTest
     * Package: yuyi05
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/11/19 0019 15:13
     */
    public class UserTest {
        public static void main(String[] args) {
            User u1=new User();
            System.out.println(u1.getInfo());
    
            User u2=new User("Tom","5664321");
            System.out.println(u2.getInfo());
    
            System.out.println();
    
            User1 u3=new User1();
            System.out.println(u3.getInfo());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    输出结果:

    image.png

    在构造器里面写的一些相同的代码,可以写入代码块中。(以前是用this()相互调用)

    (2)补充

    ⚡注意

    从刚才的例子来看,代码块可用可不用,但是有一种情况代码块还是有必要用的。

    静态代码块是用来初始化类的信息,假设这个类里面有一个静态的属性,这个属性现在需要赋值,要么显示赋值,要么在代码块里面赋值

    构造器里面就不用了(构造器主要用来初始化对象的信息),在构造器里面给静态的属性赋值,可以赋值但不推荐,静态只有一份,若是每造一个对象在构造器里就给它赋一个值,那么就会把已有的对象的值也给影响了,所以在构造器里面不要去操作静态的

    有些时候,用显示赋值不是特别靠谱,这个时候就要用静态代码块了。

    比如:

    private static DataSource dataSource = null;
    
    static{
    	InputStream is = null;
    	try {
    		is = DBCPTest.class.getClassLoader().getResourceAsStream("dbcp.properties");
    		Properties pros = new Properties();
    		pros.load(is);
    		//调用BasicDataSourceFactory的静态方法,获取数据源。
    		dataSource = BasicDataSourceFactory.createDataSource(pros);
    	} catch (Exception e) {
    		e.printStackTrace();
    	}finally{
    		if(is != null){
    			try {
    				is.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}		
    		}		
    	}		
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    这里要用到以后要说的“异常”,可以暂时不用看。看这些代码就好了:

    private static DataSource dataSource = null;
    
    static{
    	InputStream is = null;
        
    		is = DBCPTest.class.getClassLoader().getResourceAsStream("dbcp.properties");
    		Properties pros = new Properties();
    		pros.load(is);
    		//调用BasicDataSourceFactory的静态方法,获取数据源。
    		dataSource = BasicDataSourceFactory.createDataSource(pros);
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    现在声明了一个DataSource类型的静态变量dataSource,并且给它赋一个值,一方面可以直接给它赋值,另一方面可以通过静态代码块去赋。

    此时直接显示赋值不靠谱:

    image.png

    dataSource赋值的时候,一行代码搞不定,需要提前准备很多东西(这个变量赋值又要参数,又要方法,不适合在一行直接定义),显示赋值不靠谱,放在构造器也不合适,只能放在静态代码块中。


    若此时通过new,那么直接显示赋值就可以了,但是现在是通过一个方法调用返回的值是这个类型的,但是现在这个返回的一行代码也搞不定,因为参数pros也需要通过好几行代码才能搞定,而那么多行代码是执行语句,不可以在显示赋值的时候写。

    构造器里面?每造一次对象都要执行一遍,若此时这些代码所在的类不打算造对象了,既然不造对象,那要构造器也没啥用。况且每调用一次构造器,这些代码都执行一遍,没有必要,因为静态的执行一次就够了。所以不能放在构造器中。

    放在静态方法里面?比如给dataSource变量设置一个set方法,但是晚了,我希望的是类一加载完,它就执行好了。

    这时候显示不能赋值,构造器不让用,set方法也不让用,就得是代码块啦。

  • 相关阅读:
    WAMP和PHPStorm安装(Win10)
    计算机科学的奇趣探索
    【12】基础知识:React ajax
    激光slam学习
    合合信息财务自动化解决方案亮相腾讯全球数字生态大会,助力企业财务合规建设
    API是什么?解密API背后的奥秘
    快来直播带你了解中国互联网大厂布局元宇宙现状如何?
    详解supervisor配置与案例
    苹果测试版最新发行说明,iOS 15.4支持戴口罩解锁,Dropbox和OneDrive的云存储功能被打破
    STM32 HAL 库实现乒乓缓存加空闲中断的串口 DMA 收发机制,轻松跑上 2M 波特率
  • 原文地址:https://blog.csdn.net/m0_55746113/article/details/134493071