Java面向对象(基础)-- 类的成员之三:构造器(Constructor)


类的成员之三: 构造器(constructor),又叫 构造方法(和一般的方法不一样)

类的成员,前面还有属性和方法,还没有来得及更,先往后走,有空我再更。学到这里的应该都知道吧~

一、介绍

(1)理解和作用

【构造器的理解】

我们new完对象时,所有成员变量都是默认值,如果我们需要赋别的值,需要挨个为它们再赋值,太麻烦了。

我们能不能在new对象时,直接为当前对象的某个或所有成员变量直接赋值呢? 可以,Java给我们提供了 构造器(Constructor) ,也称为 构造方法

构造器非常常用,一个类里面一定会有构造器

即使是抽象类(这个类不能造对象),也有构造器。

constructor :n. 建设者、建造者

construct:v. 建设、建造、创造

construction: n. 建设、建造 CCB

【构造器的作用】

作用1:搭配new关键字,创建类的对象

作用2:在创建对象的同时,可以给对象的相关属性赋值

new对象,并在new对象的时候为实例变量赋值。

举例:Person p = new Person(“Peter”,15) ;

解释:如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的构造器中加入完成“洗澡”的程序 代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们 要“洗澡”了。

(2) 构造器的语法格式

[修饰符] class 类名{
    [修饰符] 构造器名(){
    	// 实例初始化代码
    }
    [修饰符] 构造器名(参数列表){
    	// 实例初始化代码
    }
}

说明:

  1. 构造器名必须与它所在的类名必须相同
  2. 它没有返回值,所以不需要返回值类型,也不需要void
  3. 构造器的修饰符只能是权限修饰符,不能被其他任何修饰。比如,不能被static、final、 synchronized、abstract、native修饰,不能有return语句返回值。

【举例】
image.png

之前用过的Scanner:

Scanner scan =new Scanner(System.in);

Scanner()就是一个构造器,构造器里面有形参,这里传入了一个实参System.in。

二、举例剖析

💀举例

(1)构造器在哪

比如现在创建一个类【Person.java】:

package yuyi.exer02;

/**
 * ClassName: Person
 * Package: yuyi.exer02
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/10/23 0023 8:43
 */
public class Person {
    //属性(先不考虑权限的问题)
    String name;
    int age;

    //方法
    public void eat(){
        System.out.println("人吃饭");
    }
    public void sleep(int hour){
        System.out.println("每天睡眠"+hour+"小时");
    }
}

再创建一个测试类【PersonTest.java】:

package yuyi.exer02;

public class PersonTest {
    public static void main(String[] args) {
        //创建类的对象
        Person p1=new Person(); //类型 变量名 =new 具体对象

        //通过对象来调属性、调方法
        p1.eat();
    }
}

其实Person()就是构造器:
image.png

点击这个位置,创建新的字节码文件:(反编译)
image.png

在out文件夹下,找到相应目录,可以看到被隐藏的构造器:(记得点左上角刷新一下)
image.png


(2)权限问题

若将Person类的修饰符Public去掉:
image.png

再看一下字节码文件:
image.png

可以看到,默认生成的构造器的权限与类声明的权限一致。

(3)声明构造器

构造器声明的格式:权限修饰符 类名(形参列表){}

①隐藏的构造器

上面可以看到,隐藏的构造器是这样的:

//构造器
public Person(){

}

如图:
image.png

若在Person构造器里面加上输出语句:

//构造器
public Person(){
	System.out.println("我是构造器");
}

可以在测试类里面运行出来:
image.png


②显示的构造器

我们可以显示的声明其他构造器。

package yuyi.exer02;

public class Person {
    //属性(先不考虑权限的问题)
    String name;
    int age;

    //默认构造器
    /*public Person(){
        System.out.println("我是构造器");
    }*/

    //声明其他构造器
    public Person(int a){    //参数一般考虑对类中属性赋值
        age=a;  //通过这个构造器,造对象的同时把属性age赋值
    }

}

同样可以在测试类里面创造对象,但此时会看到一个报错:
image.png

报错内容:
image.png

一旦类中显示声明了构造器,则系统不再提供默认的空参的构造器。

若此时还想用这个空参的构造器,需要自行定义:
image.png


显示构造之后,可以在测试类里面赋值并输出:

public class PersonTest {
    public static void main(String[] args) {
        //创建类的对象
        Person p2=new Person(1);
        System.out.println(p2.age);
    }
}

输出结果:
image.png

(4)声明多个构造器

在一个类中可以声明多个构造器,比如再声明一个,对name属性进行初始化:

public Person(String n){
        name=n;
}

或者对name属性和age属性同时给初始化:

public Person(String n,int a){
        name=n;
        age=a;
}

这些构造器构成重载。

再比如String:(API)
image.png

(5)构造器重点总结说明

构造器声明的格式:权限修饰符 类名(形参列表){}

4种权限都能用来修饰构造器。

没有返回值类型,直接写构造器的名字。

小括号里面是形参列表。

大括号里面是构造器体。

创建类以后,在没有显示提供任何构造器的情况下,系统会默认提供一个空参的构造器,且构造器的权限类声明的权限相同。

一旦类中显示声明了构造器,则系统不再提供默认的空参的构造器。

一个类中可以声明多个构造器,彼此之间构成重载。

三、练习

(1)练习1

🌋题目描述

(1)定义Student类,有4个属性:

String name;

int age;

String school;

String major;

(2)定义Student类的3个构造器:

  • 第一个构造器Student(String n, int a)设置类的name和age属性;
  • 第二个构造器Student(String n, int a, String s)设置类的name, age 和school属性;
  • 第三个构造器Student(String n, int a, String s, String m)设置类的name, age ,school和major属性;

(3)在main方法中分别调用不同的构造器创建的对象,并输出其属性值。

🤺代码

package anli;

public class Student {
    //属性
    String name;
    int age;
    String school;
    String major;

    //构造器
    public Student(String n, int a){
        name=n;
        age=a;
    }
    public Student(String n, int a, String s){
        name=n;
        age=a;
        school=s;
    }
    public Student(String n, int a, String s, String m){
        name=n;
        age=a;
        school=s;
        major=m;
    }
}

class StudentTest{
    public static void main(String[] args) {
        Student one=new Student("张三",19);
        Student two=new Student("李四",20,"哈佛");
        Student three=new Student("王强",22,"北大","硕士");
        System.out.println("name="+one.name+",age="+one.age);
        System.out.println("name="+two.name+",age="+two.age+",school="+two.school);
        System.out.println("name="+three.name+",age="+three.age+",school="+three.school+",major="+three.major);

    }
}

⚡输出结果
image.png

👻注意

①构造器没有初始化的属性,默认值是null:(String类型举例)
image.png

②小技巧

在调用构造器的时候,因为有很多重载,所以参数不同,可以点击小括号,将光标放在小括号内,按Ctrl+P就可以显示各个参数:
image.png

③可以在Student方法内定义一个方法,方便输出。

public class Student{
    //...
    public String getInfo(){
        return "name= "+name+",age= "+age+",school= "+school+",major= "+major;
	}
}

在测试类里面调用:

class StudentTest{
    public static void main(String[] args) {
        Student four=new Student("黎明",45,"海淀大学","医科");
        System.out.println(four.getInfo());
        //构造器的作用:搭配new创建对象、通过参数的方式给创建的对象的相关属性赋值
    }
}

输出结果:
image.png

(2)练习2

🌋题目描述

编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,

同时声明公共方法访问私有变量。此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。

angle:角

angel:天使

🤺代码

【TriAngle.java】

package anli;

/**
 * ClassName: TriAngle
 * Package: anli
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/10/23 0023 11:16
 */
public class TriAngle {
    //①属性
    private double base;   //底边长
    private double height; //高


    //②方法
    //1.1设置底边长
    public void setBase(double a){
        base=a;
    }
    //1.2获得底边长
    public double getBase(){
        return base;
    }

    //2.1设置高
    public void setHeight(double b){
        height=b;
    }
    //2.2获得高
    public double getHeight(){
        return height;
    }

    //求面积的方法
    public double findArea(){   //不需要形参,调用方法直接使用底边长和高即可
        return base * height /2;
    }


    //③构造器
    //习惯上给一个类提供构造器的时候,会先写一个空参构造器
    public TriAngle(){

    }
    public TriAngle(double b,double h ){
        base=b;
        height=h;
    }

}

【TriAngleTest.java】

package anli;

/**
 * ClassName: TriAngleTest
 * Package: anli
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2023/10/23 0023 11:17
 */
public class TriAngleTest {
    public static void main(String[] args) {
        //创建TriAngle实例1
        TriAngle t1=new TriAngle();
        //属性被私有化了,要通过调用方法来设置属性
        t1.setBase(3.4);
        t1.setHeight(2.3);
        System.out.println("面积为:"+t1.findArea());

        //创建TriAngle实例2
        TriAngle t2=new TriAngle(2.4,4.5);  //通过构造器给属性赋值
        //输出看一下是否真的赋值了
        System.out.println("底边长为:"+t2.getBase());
        System.out.println("高为:"+t2.getHeight());
        System.out.println("面积为:"+t2.findArea());
    }
}

记得看注释哦~

get、set不会写的看一下这一篇:https://blog.csdn.net/m0_55746113/article/details/133980641?spm=1001.2014.3001.5501

⚡输出结果
image.png

(3)练习3

🌋题目描述

1、写一个名为Account的类模拟账户。该类的属性和方法如下图所示。

该类包括的属性:账号id,余额balance,年利率annualInterestRate;

包含的构造器:自定义

包含的方法:访问器方法(getter和setter方法),取款方法withdraw(),存款方法deposit()。

提示:在提款方法withdraw中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。

image.png

2、创建Customer类。

a. 声明三个私有对象属性:firstName、lastName和account。

b. 声明一个公有构造器,这个构造器带有两个代表对象属性的参数(f和l)

c. 声明两个公有存取器来访问该对象属性,方法getFirstName和getLastName返回相应的属性。

d. 声明setAccount 方法来对account属性赋值。

e. 声明getAccount 方法以获取account属性。

image.png

3、写一个测试程序。

(1)创建一个Customer ,名字叫 Jane Smith, 他有一个账号为1000,余额为2000元,年利率为 1.23% 的账户。

(2)对Jane Smith操作。

存入 100 元,再取出960元。再取出2000元。

打印出Jane Smith 的基本信息:

成功存入 :100.0

成功取出:960.0

余额不足,取款失败

Customer [Smith, Jane] has a account: id is 1000, annualInterestRate is 1.23%, balance is 1140.0

🤺代码

【Account.java】

package anli;

/**
 * ClassName: Account
 * Package: anli
 * Description:
 * 该类包括的属性:账号id,余额balance,年利率annualInterestRate;
 * 包含的构造器:自定义
 * 包含的方法:访问器方法(getter和setter方法),取款方法withdraw(),存款方法deposit()。
 *
 * 提示:在提款方法withdraw中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。
 * @Author 雨翼轻尘
 * @Create 2023/10/23 0023 11:59
 */
public class Account {
    //属性
    private int id; //账号
    private double balance; //余额
    private double annualInterestRate;  //年利率

    //构造器
    public Account(){

    }
    public Account(int i,double b,double a){
        id=i;
        balance=b;
        annualInterestRate=a;
    }

    //方法
    //1.1设置账号
    public void setId(int i){
        id=i;
    }
    //1.2获得账号
    public int getId(){
        return id;
    }

    //2.1设置余额
    public void setBalance(double b){
        balance=b;
    }
    //2.2获得余额
    public double getBalance(){
        return balance;
    }

    //3.1设置年利率
    public void setAnnualInterestRate(double a){
        annualInterestRate=a;
    }
    //3.2获得年利率
    public double getAnnualInterestRate(){
        return annualInterestRate;
    }

    //取钱
    public void withdraw(double amount){
        if(amount<=balance && amount> 0){    //说明余额够
            balance-=amount;
            System.out.println("成功取出:"+amount);
        }else{
            System.out.println("余额不足,取款失败~");
        }
    }
    //存钱
    public void deposit(double amount){
        if(amount>=0){  //充入的钱是正数
            balance+=amount;
            System.out.println("成功存入: "+amount);
        }
    }

}

【Customer.java】

package anli;

/**
 * ClassName: Customer
 * Package: anli
 * Description:
 * a. 声明三个私有对象属性:firstName、lastName和account。
 * b. 声明一个公有构造器,这个构造器带有两个代表对象属性的参数(f和l)
 * c. 声明两个公有存取器来访问该对象属性,方法getFirstName和getLastName返回相应的属性。
 * d. 声明setAccount 方法来对account属性赋值。
 * e. 声明getAccount 方法以获取account属性。
 * @Author 雨翼轻尘
 * @Create 2023/10/23 0023 12:37
 */
public class Customer {
    //属性
    private String firstName;
    private String lastName;
    private Account account;    //account是自定义类属性
    //在一个类(Customer)里面可以声明另外一个类(Account)的成员变量,
    // 另外这个类可以是系统提供现成的(比如String),也可以是自定义类(Account)


    //构造器
    //在创建对象的时候,并没有给account赋值,此时account是NULL,可以在下面的方法中对account属性赋值
    public Customer(String f,String l){
        firstName=f;
        lastName=l;
    }

    //方法
    //1.针对姓名只有get方法(相当于给名字属性私有化之后,并没有提供set方法,就是一旦设置好之后就不允许再改变了)
    public String getFirstName(){
        return firstName;
    }
    public String getLastName(){
        return lastName;
    }

    //2.针对account提供get和set方法
    public void setAccount(Account a){
        account=a;
    }
    public Account getAccount(){
        return account;
    }

}

【CustomerTest.java】

package yuyi.exer01.exe01.test2;

import anli.Account;
import anli.Customer;

/**
 * ClassName: CustomerTest
 * Package: yuyi.exer01.exe01.test2
 * Description:
 *(1)创建一个Customer ,名字叫 Jane Smith, 他有一个账号为1000,余额为2000元,年利率为 1.23% 的账户。
 *(2)对Jane Smith操作。
 * 存入 100 元,再取出960元。再取出2000元。
 * 打印出Jane Smith 的基本信息:
 *
 * 成功存入 :100.0
 * 成功取出:960.0
 * 余额不足,取款失败
 * Customer [Smith, Jane] has a account: id is 1000, annualInterestRate is 1.23%, balance is 1140.0
 *
 * @Author 雨翼轻尘
 * @Create 2023/10/23 0023 16:24
 */
public class CustomerTest {
    public static void main(String[] args) {
        //1.创建Customer实例
        Customer customer=new Customer("Jane","Smith"); //通过构造器对类中的属性赋值

        //2.创建账户
        Account account=new Account(1000,2000,0.0123);

        //3.客户与账户建立联系
        customer.setAccount(account);


        //4.针对于客户的账户进行取钱、存钱的操作
        //方法一
        /*不要直接通过account进行操作,就好像银行在操作一样,现在要体现自己操作
        account.deposit(100);//存钱
        account.withdraw(960);//取钱
        account.withdraw(2000);//取钱*/

        //方法二
        //先通过客户找到账户,拿着账户再去存钱
        customer.getAccount().deposit(100); //存钱100
        customer.getAccount().withdraw(960);    //取钱960
        customer.getAccount().withdraw(2000);   //取钱2000

        //5.输出客户信息
        System.out.println("Customer ["+customer.getLastName()+", "+customer.getFirstName()+"] has a account: " +
                "id is "+customer.getAccount().getId()+
                ", annualInterestRate is "+ customer.getAccount().getAnnualInterestRate()*100+
                "%, balance is "+ customer.getAccount().getBalance());

    }
}

⚡输出结果
image.png

👻注意

①重要代码分析
Customer.png

②补充知识点

	//1.创建Customer实例
	Customer customer=new Customer("Jane","Smith"); //通过构造器对类中的属性赋值

    //2.创建账户
    Account account=new Account(1000,2000,0.0123);	//创建了一个账户,账户的名字叫account

    //3.客户与账户建立联系
    customer.setAccount(account);	//账户的名字account(变量)赋值给customer的setAccount属性

上面代码的第2个和第3个可以合并起来:

customer.setAccount(new Account(1000,2000,0.0123));	
//在堆空间创造了一个对象new Account(1000,2000,0.0123),这个对象没有名字,叫做匿名对象

匿名对象:创建的对象没有名字。


【举例】

在main方法里面,取1000块钱:

//关于匿名对象
new Account(1001,2000,0.0123).withdraw(1000);   //取钱

输出结果:
image.png

若想看一下刚才创建的对象它的账户余额,这样调用是不可行的:

System.out.println(new Account(1001, 2000, 0.0123).getBalance());//不可行,这里又会创建一个新的对象

输出结果:
image.png

上面造的匿名对象Account…,下面输出的时候还想拿到那个对象,是不行的

匿名对象只能用一次,后边就找不到了。

在java里面调用一个对象或一个值,都是通过变量名来调用的。

之前我们都是将对象赋值给一个具体的对象,比如:

Account account=new Account(1000,2000,0.0123);

若想拿到这个对象,直接拿变量名account来操作就可以了。

匿名的话就只能调用一次啦。


那匿名对象咋用嘞?

开发当中,通常就是这样使用:
image.png

当造好的对象被赋值给了一个变量,紧接着又调用了这个变量,这个变量后边也没有用,就可以这样使用。

1.匿名对象往往只能被调用一次。

2.通常匿名对象作为实参传递给方法的形参。


小Tips:

customer.setAccount(new Account(1000,2000,0.0123));	

其实,在setAccount方法里面,针对a是可以多次调用的:
image.png

所谓的匿名对象传进setAccount内之后就有名了,在setAccount方法里面可以多次调用。


【注】纯手敲难免有误,欢迎各位读者指正,感兴趣的欢迎关注专栏:http://t.csdnimg.cn/XEkfM,后续会持续更新,关注博主不迷路~

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

雨翼轻尘

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

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

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

打赏作者

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

抵扣说明:

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

余额充值