Java中你真的会用Constructor构造器吗之看完本篇你就真的会了

时间:2021-08-17 16:58:14

引言

相信大家对于java里的构造器应该都是有了解的,这次我们来了解一些构造器的不同使用方式,了解构造器的调用顺序,最后可以灵活的在各种情况下定义使用构造器,进一步优化我们的代码;

构造器简介

还是简单介绍一下构造器到底是什么吧,
构造器是类中一种特殊的方法,通过调用构造器来完成对象的创建,以及对象属性的初始化操作。

构造器定义方式:

?
1
2
3
[修饰符列表] 构造器名(形式参数列表){
     构造方法体;
 }

构造器有以下几个特点:

  • 构造器名和类名一致;
  • 构造器用来创建对象,以及完成属性初始化操作;
  • 构造器返回值类型不需要写,包括 void 也不能写
  • 构造器的返回值类型实际上是当前类的类型
  • 一个类中可以定义多个构造器,这些构造器构成方法重载

构造器的使用其实很常见,调用语法为:new 构造器名(实际参数列表) ,假如我们现在有一个Person类,调用默认构造器:

?
1
Person p = new Person(); // 这里的Person()其实就是调用的默认构造器!!

构造器的使用需要注意:
当一个类没有显式的定义任何构造器的时候,系统默认提供无参数构造器,当显式的定义构造器之后,系统不再提供无参数构造器。无参数构造器又叫做缺省构造器,或默认构造器;

构造器重载

虽然系统会给我们提供默认构造器并赋予初始值,我们自己也可以显式的指定初始值,但是可不可以多种构造器同时存在一个类中呢?
这就需要重载构造器,因为构造器也是方法的一种,方法都可以重载,构造器当然也可以;
构造器重载方式和方法重载差不多,只需要构造器名相同,参数列表不同就可以了;

测试代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ConstructorOverloadTest {
    String name;
    int age;
 
    // 默认构造器(无参构造器)
    ConstructorOverloadTest() {}
    // 含参构造器 重载版
    ConstructorOverloadTest(String myName, int myAge) {
        this.name = myName;
        this.age = myAge;
    }
    public static void main(String[] args) {
        // 调用无参构造器
        var p1 = new ConstructorOverloadTest();
        System.out.println("p1的初始化结果为:");
        System.out.println("姓名 :" + p1.name);
        System.out.println("年龄:" + p1.age);
        // 调用有参构造器
        var p2 = new ConstructorOverloadTest("张三", 18);
        System.out.println("p2的初始化结果为:");
        System.out.println("姓名 :" + p2.name);
        System.out.println("年龄:" + p2.age);
    }
}

输出结果为:

p1的初始化结果为:
姓名 :null
年龄:0
p2的初始化结果为:
姓名 :张三
年龄:18

当然这里只写了一个重载版本,还可以定义多个重载版本,这里就不列举了;我们只需要能够根据实际情况使用恰当的重载就可以了,不用都写出来;

构造器间的相互调用

如果系统中有多个构造器,并且我们想要通过一个构造器A调用另一个构造器B,该怎么办?
可能有人会想到调用构造器肯定要创建一个对象啊,所以直接new一个不就可以了嘛; 但是我们通过一个构造器调用另一个构造器的目的就是为了简化代码的,这样反而又多此一举了;
如果不new一个新的对象,那么我们可以通过 this引用 来调用相应的构造器;

还是不太明白?看看下面的代码!
测试代码如下:

?
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
public class ConstructorTest01 {
    public static void main(String[] args) {
        // 调用两个参数的构造器
        Person p1 = new Person("张三", 18);
        System.out.println("两个参数的构造器初始化结果为:");
        System.out.println("姓名:" + p1.name);
        System.out.println("身份证号:" + p1.idNum);
        System.out.println("年龄:" + p1.age);
 
        // 调用三个参数的构造器
        Person p2 = new Person("李四", "6666666", 20);
        System.out.println("三个参数的构造器初始化结果为:");
        System.out.println("姓名:" + p2.name);
        System.out.println("身份证号:" + p2.idNum);
        System.out.println("年龄:" + p2.age);
    }
}
class Person {
    String name;
    String idNum;
    int age;
 
    // 有两个参数的构造器
    Person(String myName, int myAge) {
        this.name = myName;
        this.age = myAge;
    }
    // 有三个参数的构造器
    Person(String myName, String myIdNum, int myAge) {
        // 通过this调用两个参数的构造器
        this(myName, myAge);
        this.idNum = myIdNum;
    }
}

输出结果为:

两个参数的构造器初始化结果为:
姓名:张三
身份证号:null
年龄:18
三个参数的构造器初始化结果为:
姓名:李四
身份证号:6666666
年龄:20

通过this调用有一点需要注意:
使用this调用另一个重载的构造器只能在构造器中使用,且必须作为构造器执行体的第一条语句

可能有人会问:如果在有三个参数的构造器里面不用this指针,而是直接把上一个构造器的代码复制过来不行吗?
当然可以,但是不建议;我们得知道为什么要存在this这个调用构造器的方法,它不是无缘无故存在的;在软件开发时有一个原则:不要把相同代码重复写两次以上;因为一旦一个构造器内的初始代码需要修改,那么很有可能其他的构造器初始代码也要跟着修改,如果构造版本多的话是非常麻烦的;而使用this恰恰可以避免这个问题,只需要修改一个地方,其他几个构造器就随着更改了;这样的代码不仅更加简洁,而且降低了维护成本;

子类构造器调用父类构造器

继承有一个规则是:当继承发生后,子类不会获得父类的构造器;
但是子类的构造器可以通过一定方法区调用父类构造器,类似于通过this引用调用重载的构造器;
而子类构造器调用父类的构造器不用this关键字,这里有一个新的关键字:super

super和this用法差不多,使用它就可以实现子类构造器调用父类的构造器;

看个代码就明白了:
测试代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Person {
    String name;
    int age;
    // 父类的构造函数
    Person(String myName, int myAge) {
        this.name = myName;
        this.age = myAge;
    }
}
public class Kids extends Person{
    String school;
    // 子类的构造函数
    Kids(String myName, int myAge, String mySchool) {
        // 通过super来调用父类构造器初始化过程
        super(myName, myAge);
        this.school = mySchool;
    }
    public static void main(String[] args) {
        Kids k = new Kids("张三", 5, "奥特曼小学");
        System.out.println("name:" + k.name);
        System.out.println("age:" + k.age);
        System.out.println("school:" + k.school);
    }
}

输出结果为:

name:张三
age:5
school:奥特曼小学

通过代码可以看出来super确实和this非常像,无非就是super调用父类构造器,this调用同一个类的重载的构造器;
且使用super也需要注意:
super调用父类构造器也必须在子类构造器执行体的第一行,所以this和super不会同时出现;

构造器的调用顺序

这里先看一个代码:

?
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
class Creature {
    Creature() {
        System.out.println("Creature的无参构造器的调用");
    }
}
class Person extends Creature {
    Person(String name) {
        System.out.println("Person的一个参数构造器的调用");
    }
    Person(String name, int age) {
        // this调用同一个类中重载的构造器
        this(name);
        System.out.println("Person的两个参数构造器的调用");
    }
}
public class Kids02 extends Person {
    Kids02() {
        // 显式调用父类的两个参数的构造器
        super("张三", 18);
        System.out.println("Kids02的无参构造器的调用");
    }
    public static void main(String[] args) {
        // 创建一个Kids02对象
        new Kids02();
    }
}

这个代码中,Person类继承了Creature类,Kids02类继承了Person类,Perosn类中又通过this调用同一个类中重载的构造器,
Kids02类中用super 显式调用父类的两个参数的构造器;
那么输出是什么呢?到底先调用的是谁的构造器,最后调用的谁的构造器?

输出如下:

Creature的无参构造器的调用
Person的一个参数构造器的调用
Person的两个参数构造器的调用
Kids02的无参构造器的调用

通过这个代码和结果,可以总结出来,父类构造器总在子类构造器之前执行,或者可以说:
创建任何对象总是从该类所在继承树最顶层类的构造器开始执行的,然后依次向下执行;
对于this和super也是一样;

这个代码好好理解一下,就会对构造器间的关系体会更深;

总结

对象的初始化离不开构造器,对构造器的学习真正需要的还是大量的练习,这些内容也是需要熟练掌握的;这关乎着你在实际开发应用过程中对整个代码的影响和对象能否恰到好处的初始化;希望你能够真正学会并应用到这些方法,且通过这篇文章能有所收获!

ps:如果内容有问题欢迎讨论!!

到此这篇关于Java中你真的会用Constructor构造器吗之看完本篇你就真的会了的文章就介绍到这了,更多相关Java 构造器 Constructor内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/YXXXYX/article/details/120164551