Java学习笔记【1】:Constructor

Java学习系列文章目录

Java基本语法



前言

本文主要记载了在Java课程学习中遇到的与类的构造函数函数有关的问题及个人理解


一、构造函数的定义

Java的构造函数,也叫构造方法,是Java中一种特殊的函数。构造函数的函数名必须与对应的类名相同,且无返回值。`

唯一能够调用构造函数的方法就是新建一个类(或者是新建一个这个类的子类,并在创建这个类的子类的时候,在该子类的构造函数里面调用)。

语法结构为:

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

二、使用示例

1. 构造函数

作为一个特殊的方法,构造函数的形式与普通的方法类似,但需要注意的是,构造函数不可以有返回值,同时也说明,在构造函数中,不可以有return语句(因为函数无返回类型)!

代码如下(示例):

// 假设我们现在有一个class为Duck,则该类最基础的构造函数为
public Duck() {
}

需要注意的是,如果你在创建对象的时候,没有显式的编写构造函数,那么编译器会隐式的为你的class创建一个与上面代码相类似的最基本的构造函数。

2. 有参构造函数

如果在类中重写(overload)构造函数,可以向构造函数中 传递参数。

代码如下(示例):

// 使用与上一个示例相同的class Duck
public Duck(int size, String name) {
	// code
}

这里只需要知道可以向构造函数中传入参数即可,用法在下面具体阐述
需要注意的是,当你定义了一个有参的构造函数后,编译器将不会再自动为你生成无参的构造函数,如果需要使用无参的构造函数,需要自己手动编写(这一点在继承中十分重要)。


三、用法总结

1. 判断是否成功创建变量

可以打印相关语句来表明是否成功创建对象,同时也可以为对象设置默认的初始值(通常我们很需要这点)。

代码如下(示例):

// 使用与上一个示例相同的class Duck,并在class DuckTest中创建一个Duck
public class DuckTest {
    public static void main(String[] args) {
        Duck myDuck = new Duck();
    }
}

class Duck {
	private int size;
    private String name;
    public Duck() {
        size = 10;
        name = "duck";
        System.out.println("Quark");
    }
}

输出为:Quark

2. 对创建的对象初始化

当我不希望单独使用set方法去繁琐地设置每一个实例变量。也就相当于完成了setter的功能。

// 继续使用与上一个示例相同的class Duck,并在class DuckTest中创建一个Duck
import java.util.Scanner;

public class DuckTest {
    public static void main(String[] args) {
        Scanner ip = new Scanner(System.in);
        // 创建一个大小为50,名为Donald的Duck
        Duck myDuck = new Duck(ip.nextInt(), ip.next());
        System.out.println("The duck size is " + myDuck.size + ", the duck name is " + myDuck.name);
    }
}

class Duck {
    private int size;
    private String name;
    public Duck() {
        System.out.println("Quark");
    }
    public Duck(int size, String name) {
        this.name = name;
        this.size = size;
    }
}

输入为:50,Donald
输出为:The duck size is 50, the duck name is Donald
p.s. 为了方便输出,此处的Duck的实例变脸设置为public

3. 继承中的构造函数

3.1. 父类、子类以及继承之间的关系

当我们在创建某个对象的时候(我们只能通过new来产生新对象),对象会取得所有实例变量所需的空间,同时也包括这个对象所继承的所有东西。

因此我们可以知道,当我们创建一个新对象时,所有继承下来的构造函数都会被执行。 也就是说,当子类的构造函数在被执行的时候,他所做的第一件事就是去执行父类的构造函数,这会如同连锁反应般,一直执行到Object这个类(虽然没什么用)。

可以这样理解,在有子类之前,肯定会先有父类(不然子类无法继承,也就没有办法创建一个新的子类对象,可以在cmd中使用javac去尝试),就好比没有父亲就不会有儿子。同时,子类可能会根据父类的状态来继承方法(即父类的实例变量)。综上所述,并结合前面的定义我们可以得出结论:父类的构造函数,在子类被创建的时候,一定会被执行。

3.2. super()

一个在子类中调用父类方法的方法(详细使用方法可以移步csdn搜索)

若要在子类的构造函数中显式的调用父类的构造函数,则需要使用super()方法,此时super()可以等价与父类的类名。

需要注意的是,因为super()此时在子类的构造函数中代表的是父类的构造函数,所以必须在子类构造函数的第一行使用。可以理解为,在执行创建子类之前,必须先创建父类,即使用父类的构造函数。

3.3. 使用样例

和前面一样,当我们不在子类的构造函数中使用super()方法的时候,编译器会隐式的调用super()方法。

先介绍一种会报错的写法:

public class Creature {
    int weight;
    String name;
    Creature(int weight, String name) {
        this.weight = weight;
        this.name = name;
    }
}

class Rabbit extends Creature {
    String furType;
    int speed;
    Rabbit(String furtype, int speed){
        this.furType = furtype;
        this.speed = speed;
    }
}

这是一个一开始一直困扰我和我同学的问题。此时我们会发现,编译器会报错:“没有可以使用的构造函数”。
这是因为,父类overload了一个有参的构造函数,这时候编译器将不会给class Creature自动生成一个无参的构造函数,而子类的构造函数会隐式的使用super()去调用父类的无参构造函数,这就导致了子类的构造函数无法使用父类的构造函数去构造一个新的子类。
这个问题有两个解决方法:1.在父类中显示的编写一个无参构造函数;2. 在子类构造函数的第一行,显示的使用super()去调用父类的有参构造函数。

下面来看正确的写法:

public class Creature {
    int weight;
    String name;
    Creature() {}
    Creature(int weight, String name) {
        this.weight = weight;
        this.name = name;
    }
}

class Rabbit extends Creature {
    String furType;
    int speed;
    Rabbit(String furtype, int speed){
    	// 父类中有无参构造函数,可以隐式调用
        this.furType = furtype;
        this.speed = speed;
    }
}

class Turtle extends Creature {
    String shellType;
    int speed;
    Turtle(String shelltype, int speed) {
        super(10, "TMNT"); // 显式调用父类的有参构造函数,也需要传参
        this.shellType = shelltype;
        this.speed = speed;
    }
}

3.4. 方法this()

如果有某个overload后的构造函数除了不能处理不同类型的参数之外,可以处理所有的工作,这个时候,我们可以使用一个调用this()方法,对对象本身进行引用。

概括来说,使用this()方法可以从某个构造函数调用同一个类的另外一个构造函数。

this()方法只能用于构造函数的第一行,也就是说,一个构造函数只能选择this或者super之一。

代码如下(示例):

public class Creature {
    int weight;
    String name;
    Creature() {}
    Creature(int weight, String name) {
        this.weight = weight;
        this.name = name;
    }
    
    public static void main(String[] args) {
        Turtle t = new Turtle("Blue", 20);
        System.out.println(t.weight + ", " + t.name + ", " + t.shellType + ", " + t.speed);
    }
}
class Turtle extends Creature {
    String shellType;
    int speed;
    Turtle() {
        this("Green", 500); // 无参构造函数以默认的shellType和speed调用真正的构造函数
    }
    // 这才是真正的构造函数
    Turtle(String shelltype, int speed) {
        super(10, "TMNT");
        System.out.println(shelltype + ", " + speed);
        this.shellType = shelltype;
        this.speed = speed;
    }
}

输出为:
Blue, 20
10, TMNT, Blue, 20

4. 总结

4.1. 构造函数的引用

(方法修饰符中有static时)普通方法调用:类名.方法名(实参)
(方法修饰符中没有有static时): 引用.方法名(实参)

4.2. 构造函数的返回值

对于构造方法来说,”返回值类型“不需要指定。并且不能写void。

每一个构造方法执行完之后,都有返回值。但是类似“return”的语句不需要写(无返回值类型)。

构造方法结束之后,java程序自动返回值。返回类型是构造方法所在类的类型。由于返回类型是类本身,所以返回值类型不需要编写。

4.3. 构造函数的特点

  • 对于任意一个构造函数来说,他在创建一个新的对象的过程中,仅在最开始的时候使用一次。之后如果需要更改实例变量的值,需要使用setter方法。
  • 当一个类中,没有定义任何构造方法,系统默认给该类提供一个无参数的构造方法
    这个构造方法被称为缺省构造器。
  • 当一个类明确的将构造方法定义出来,那么系统不再默认为这个类提供缺省构造器。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zzzyzh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值