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

文章目录

  • 一、回顾
    • (1)三条主线
    • (2)类中可以声明的结构及作用
      • 1.结构
      • 2.作用
  • 二、代码块
    • (1)代码块的修饰与分类
      • 1. 代码块的修饰
      • 2. 代码块的分类
      • 3. 举例
    • (2) 静态代码块
      • 1. 语法格式
      • 2. 静态代码块的特点
    • (3)非静态代码块
      • 1. 语法格式
      • 2. 非静态代码块的作用
      • 3. 非静态代码块的意义
      • 4. 非静态代码块的执行特点
    • (4)举例
      • 1. 举例1
      • 2. 举例2
      • 3. 举例3
      • 4. 举例4
      • 5. 举例5
      • 6. 举例6
      • 7. 举例7
      • 8. 举例8
    • (5)重点总结
      • 1. 静态代码块
      • 2. 非静态代码块
  • 三、练习
    • (1)练习
    • (2)补充

一、回顾

(1)三条主线

面向对象三条主线:

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

②封装、继承、多态

③关键字

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

1.结构

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

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

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

2.作用

属性:基本的变量值

方法:用来体现类的功能

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

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

二、代码块

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

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

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

1. 代码块的修饰

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

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

2. 代码块的分类

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

//静态代码块
static{
    
}

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

//非静态代码块
{
    
}

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");
    }

}

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

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

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

public class BlockTest {
    public static void main(String[] args) {
        Person p1=new Person();
        p1.eat();
    }
}

执行就可以输出结果了:

image.png

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

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

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

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

(2) 静态代码块

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

1. 语法格式

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

【修饰符】 class{
	static{
        静态代码块
    }
}

2. 静态代码块的特点

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

(3)非静态代码块

1. 语法格式

【修饰符】 class{
    {
        非静态代码块
    }
    【修饰符】 构造器名(){
    	// 实例初始化代码
    }
    【修饰符】 构造器名(参数列表){
        // 实例初始化代码
    }
}

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");
    }

}

输出结果:

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");
    }

}

输出结果:

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");
    }

}

输出结果:

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");
    }

}

输出结果:

image.png

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

5. 举例5

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

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

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

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

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

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

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

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

若此时通过对象调用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);
    }

}

输出结果:

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");
    }

}

输出结果:

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");
    }
}

输出结果:

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");
}

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

//非静态代码块
{
    System.out.println("非静态代码块2");
}

{
    System.out.println("非静态代码块1");
    age=1;  //修改age的值 ,非静态代码块中可以调用非静态的属性或方法

    //非静态代码块中可以调用静态属性或方法(提前就已经加载过了)
    System.out.println("info= "+info);

}

整体代码:

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");
    }
}

输出结果:

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());
    }

💨代码

【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;
    }


}

【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());
    }
}

输出结果:

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;
    }
}

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

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

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

在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;
}

这里的变化如下:

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;
    }
}

测试类【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());
    }
}

输出结果:

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();
			}		
		}		
	}		
}

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

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);
    
}

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

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

image.png

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


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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/164919.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

两栏布局:左侧固定,右侧自适应

左侧宽度固定&#xff0c;右侧宽度自适应剩余空间 方法一&#xff1a;float margin 方法二&#xff1a;flex布局 相关HTML代码 <div class"container"><div class"left"></div><div class"main"></div> </d…

BGP基本配置

配置逻辑 完成所有路由器的IGP配置使用直连接口建立EBGP对等体关系使用环回接口建立IBGP对等体关系使用connect-interface命令修改IBGP建邻源IP地址使用next-hop-local命令修改路由传递时的下一跳属性若存在使用环回接口建立EBGP对等体关系&#xff0c;则需要建立通讯条件&…

CentOS 7 安装CMake指定版本3.21.2

背景&#xff1a;今天在CentOS 7 电脑上安装C 日志框架SpdLog-1.12.0&#xff0c;提示如下错误信息&#xff1a; [rootlocalhost build]# cmake .. && make -j CMake Error at CMakeLists.txt:3 (cmake_minimum_required):CMake 3.10...3.21 or higher is required. …

Mysql-索引

1.介绍 索引是数据库管理系统中用于提高查询速度的一种数据结构。在MySQL中&#xff0c;索引可以看作是一种特殊的表&#xff0c;其中包含了对数据表中特定列的值及其在数据表中的位置信息。通过使用索引&#xff0c;MySQL可以在不需要扫描整个表的情况下快速找到与查询条件匹…

三栏布局,中间自适应

方法一&#xff1a;两边使用float 中间使用margin 方法二&#xff1a;两边使用absolute 中间使用margin 方法三&#xff1a;flex 布局 方法四&#xff1a;grid 布局 方法一&#xff1a;相关HTML代码【两边使用float 中间使用margin】 <div class"container"…

类和对象(8):explicit,static成员,友元,内部类

一、explicit class Date { public:Date(int year 2023, int month 1, int day 1):_year(year),_month(month),_day(day){}private:int _year;int _month;int _day; };int main() {// Date d1(1); // 这是正常初始化Date d1 1;return 0; }不妨猜测一下&#xff0c;d1的初始…

2023年【安全员-A证】报名考试及安全员-A证新版试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-A证报名考试是安全生产模拟考试一点通总题库中生成的一套安全员-A证新版试题&#xff0c;安全生产模拟考试一点通上安全员-A证作业手机同步练习。2023年【安全员-A证】报名考试及安全员-A证新版试题 1、【多选…

LeetCode(29)三数之和【双指针】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 三数之和 1.题目 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复…

SpringBoot-AOP学习案例

4. AOP案例 SpringAOP的相关知识我们就已经全部学习完毕了。最后我们要通过一个案例来对AOP进行一个综合的应用。 4.1 需求 需求&#xff1a;将案例中增、删、改相关接口的操作日志记录到数据库表中 就是当访问部门管理和员工管理当中的增、删、改相关功能接口时&#xff0…

单线程的JS中Vue导致的“线程安全”问题

目录 现象分析原因 浏览器中Js是单线程的&#xff0c;当然不可能出现线程安全问题。只是遇到的问题的现象与多线程的情况十分相似&#xff0c;导致对不了解Vue实现的我怀疑起了人生… 现象 项目中用到了element-plus中的加载组件&#xff0c;简单封装了一下&#xff0c;用来保…

100.相同的树(LeetCode)

关于树的递归问题&#xff0c;永远考虑两方面&#xff1a;返回条件和子问题 先考虑返回条件&#xff0c;如果当前的根节点不相同&#xff0c;那就返回false&#xff08;注意&#xff0c;不要判断相等时返回什么&#xff0c;因为当前相等并不能说明后面节点相等&#xff0c;所以…

【每日一题】689. 三个无重叠子数组的最大和-2023.11.19

题目&#xff1a; 689. 三个无重叠子数组的最大和 给你一个整数数组 nums 和一个整数 k &#xff0c;找出三个长度为 k 、互不重叠、且全部数字和&#xff08;3 * k 项&#xff09;最大的子数组&#xff0c;并返回这三个子数组。 以下标的数组形式返回结果&#xff0c;数组中…

a标签下载文件与解决浏览器默认打开某些格式文件的问题

前言 在实际项目中&#xff0c;我们通常会遇到这么一个需求&#xff1a;后端给前端返回一个任意文件类型的完整的url路径&#xff0c;前端拿到这个路径直接通过浏览器下载文件到本地。我想大家应该都会首先想到使用HTML中的<a>标签&#xff0c;&#xff0c;因为<a>…

【深度学习实验】注意力机制(二):掩码Softmax 操作

文章目录 一、实验介绍二、实验环境1. 配置虚拟环境2. 库版本介绍 三、实验内容0. 理论介绍a. 认知神经学中的注意力b. 注意力机制&#xff1a; 1. 注意力权重矩阵可视化&#xff08;矩阵热图&#xff09;2. 掩码Softmax 操作a. 导入必要的库b. masked_softmaxc. 实验结果 ​ …

代码随想录算法训练营第25天|216.组合总和III 17.电话号码的字母组合

JAVA代码编写 216. 组合总和III 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 示例 1: 输入: k …

Spring IOC/DI和MVC及若依对应介绍

文章目录 一、Spring IOC、DI注解1.介绍2.使用 二、Spring MVC注解1.介绍2.使用 一、Spring IOC、DI注解 1.介绍 什么是Spring IOC/DI&#xff1f; IOC(Inversion of Control&#xff1a;控制反转)是面向对象编程中的一种设计原则。其中最常见的方式叫做依赖注入&#xff08;…

windows排除故障工具pathping、MTR、sysinternals

pathping 基本上可以认为它是ping和tracert的功能合体。 pathping首先对目标执行tracert&#xff0c;然后使用ICMP对每一跳进行100次ping操作。 如图&#xff0c;是一个对8.8.8.8进行pathing操作。 MTR MTR是另一个多工具合体工具。 winmtr是mtr的windows版本。 这个工具…

c盘清除文件

打开设置 搜索存储

设计模式(二)-创建者模式(2)-工厂模式

一、为何需要工厂模式&#xff08;Factory Pattern&#xff09;? 由于简单工厂模式存在一个缺点&#xff0c;如果工厂类创建的对象过多&#xff0c;使得代码变得越来越臃肿。这样导致工厂类难以扩展新实例&#xff0c;以及难以维护代码逻辑。于是在简单工厂模式的基础上&…

QFile文件读写操作QFileInFo文件信息读取

点击按钮选择路径&#xff0c;路径显示在lineEdit中 将路径下的文件的内容放在textEdit中 最后显示出来 &#xff01;file.atend()//没有读到文件尾就一直读 file.readline表示按行进行读 追加的方式进行写 要是重新写的话用file.open(QIODevice::write) 用QFileInFo来读取…