【MMBBi的Java之路】类和对象的理解(二)-this引用和对象的构造方法

文章详细解释了Java中this引用的作用,特别是在解决成员变量与局部变量同名时的区分,以及在构造方法中的应用。同时介绍了构造方法的概念,包括其特性,如自动调用、用于对象初始化,并展示了构造方法的重载。文章通过实例代码帮助理解this引用在访问成员变量和构造方法中的使用规则。
摘要由CSDN通过智能技术生成

【MMBBi的Java之路】类和对象的理解(二)-this引用和对象的构造方法

前言

本篇博客是作为上一篇博客( 【MMBBi的Java之路】关于Java中类和对象的理解)的后续,依然是为了加深我个人对Java中类和对象相关内容的理解所写的一篇博客。

this引用

为什么要有this引用

这里我们先看一段代码

//随便定义一个日期类,包含年月日三个成员变量
public class Date {
    public int year;
    public int month;
    public int day;

//然后通过setDay进行赋值
    public void setDay(int year, int month, int day) {
        year = year;
        month = month;
        day = day;
    }
//打印日期
    public void printfDate() {
        System.out.println(year+"/"+month+"/"+day);
    }
    
	public static void main(String[] args) {
	//new三个日期,并且进行赋值
    Date day1 = new Date();
	Date day2 = new Date();
	Date day3 = new Date();

	day1.setDay(2023,5,1);
	day2.setDay(2023,5,2);
	day3.setDay(2023,5,3);
	//接下来打印,按照程序流程,应该输出2023/5/1 2023/5/2 2023/5/3
	day1.printfDate();
	day2.printfDate();
	day3.printfDate();
    }
}

按照代码上面这个代码,按理说输出的应该是2023/5/1 2023/5/2 2023/5/3,可是这边实际的输出结果是这样的:
在这里插入图片描述

这是因为在setDay这个方法中,形参和Date的成员变量的名字重复了,这个时候计算机就懵逼了,到底是谁给谁赋值?成员变量给成员变量?参数给参数?参数给成员变量?成员变量给参数?这个时候就是形参给形参赋值,一个默认的0。

除此之外还有另外一个问题:三个对象day1,day2, day3 都在调用setDate和printDate函数,但是这两个函数中没有任何有关对象的说明,setDate和printDate函数如何知道打印的是那个对象的数据呢?

这个时候就是this引用来解决的问题了。

什么是this引用

this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

实际上在我们使用成员方法的时候,都会带上一个隐形的参数this,比如上面的setDay方法,他的实际参数是:

 public void setDay(Date this, int year, int month, int day)

this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收。

所以我们碰到形参和成员变量同名的情况下,可以在通过this加 ‘ . ’来引用成员变量,确保我要将形参赋值给成员变量。

public void setDay(Date this, int year, int month, int day) {
    this.year = year;
    this.month = month;
    this.day = day;
}
public void printfDate() {
   	System.out.println(this.year+"/"+this.month+"/"+this.day);
}

再次运行程序,可以看到程序输出的是我们想要的结果。
在这里插入图片描述

this的使用方法

this除了访问类的成员变量之外,还有另外两种使用方法,分别是:
访问构造方法
访问成员方法
这两种用法接下来会借助对象的构造和初始化来说明。

对象的构造以及初始化

如何初始化对象

我们知道,如果在java内部定义一个变量的时候如果不初始化,否则就会编译失败。

public static void main(String[] args) {
    int a;
    System.out.println(a);
}

在这里插入图片描述

想要通过编译,只要给上面的a附上一个初始的值即可,如果是给对象初始化,我们拿上面的Date类说明。

public static void main(String[] args) {
    Date day = new Date();
    day.printfDate();
    day.setDay(2023, 5, 1);
    day.printfDate();
}

在这里插入图片描述

我们可以看到,这边通过setDay方法给day对象进行了赋值。这边就引出了两个问题
1:每次对象创建好后都要调用SetDate方法设置具体日期,比较麻烦。
2:局部变量要初始化后才能使用,为什么字段声明之后没有给值依然可以使用?

这就引出了构造方法,可以帮助我们解决第一个问题。

构造方法

构造方法是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。

构造方法有四个特性:
我们先来看两个
1. 名字必须与类名相同
2. 没有返回值类型,设置为void也不行

public class Date {
    public int year;
    public int month;
    public int day;

	//构造方法的名字必须与类名相同
	//一般情况下我们使用public修饰
	//并且没有返回值,使用void也不行,加了void之后编译器会报错
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
        System.out.println("构造方法被调用了");
    }
    
    public void printfDate() {
        System.out.println(this.year+"/"+this.month+"/"+this.day);
    }
    public static void main(String[] args) {
    	//此处new了一个Date类型的对象(这里我使用的IDEA2022的版本,会提示我使用了构造方法。)
    	//其他较老的编译器可能不会提示。
        Date day = new Date(2023, 5, 1);
        day.printfDate();
    }
}

编译一下上面的代码,我们可以看到
在这里插入图片描述

通过上面的例子,我们看到了在new了一个对象的同时,我们直接通过构造方法进行了赋值。
注意:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。

再来看剩下两个构造方法的特性
3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
4. 构造方法可以重载

如果我们没有进行显性定义的话,编译器会帮我们生成一份默认的构造方法,并且这个默认的构造方法一定是无参的,就是我们最开始写的Date类。

//注意看这里,我们没有定义任何的构造方法,但是依然编译通过了。
public class Date {
    public int year;
    public int month;
    public int day;
    
    public void printfDate() {
        System.out.println(this.year+"/"+this.month+"/"+this.day);
    }
    
 	public static void main(String[] args) {
        Date day = new Date();
        day.printfDate();
    }

}

上述代码中没有定义任何构造方法,编译器会默认生成一个不带参数的构造方法。
但是我们一旦自己写了一个构造方法,那么编译器就不会在帮我们自己生成一个。
我们看下面这段代码

public class Date {
    public int year;
    public int month;
    public int day;

//这是一个无参的构造方法
    public Date() {
        System.out.println("无参构造方法被调用了");
    }
    
//这是一个有三个参数的构造方法
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
        System.out.println("有三个参数的构造方法被调用了");
    }


    public void printfDate() {
        System.out.println(this.year+"/"+this.month+"/"+this.day);
    }

	    public static void main(String[] args) {
	    //创建对象,没有参数
        Date day = new Date();
        System.out.println("==============================");//分割线
        //创建对象,给三个参数
        Date day2 = new Date(2023,5,1);
    }
}

在这里插入图片描述

首先,上述代码中,我们有两个相同名称的构造方法,参数列表不同,这里就构成了方法的重载。
如果我这边没有写那个无参的构造方法,那么这里创建day对象的时候,编译器会报错,无法通过。因为我创建了一个有三个参数的构造方法,编译器不会再帮我们创建一个没有参数的构造方法。

构造方法就暂时说到这里,下面我们可以回到this引用,看看this引用的另外一个使用方法。 访问构造方法。

public class Date {
    public int year;
    public int month;
    public int day;

    public Date() {
        
        //System.out.println("无参构造方法被调用了");
        //这里注释如果取消掉的话编译会报错,因为通过this引用构造方法,this必须在第一行。
        
        //此处可以通过this引用方访问带有三个参数的构造方法,
       this(2023,5,1);
       System.out.println("无参构造方法被调用了");
    }

    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
        System.out.println("有三个参数的构造方法被调用了");
    }

    public void printfDate() {
        System.out.println(this.year+"/"+this.month+"/"+this.day);
    }
    public static void main(String[] args) {
        Date day = new Date();
        day.printfDate();
    }
}

在这里插入图片描述

可以看到这里面有两个点:
一个是this引用访问其他构造方法必须是构造方法中的第一条语句。
第二个可以仔细看输出结果,访问完第三个参数的构造方法之后,还会回来继续访问剩下的代码。
此外还有一个需要注意的点就是this引用不能形成环,语法不支持,编译会报错。

在这里插入图片描述

this引用的第三个使用方法,访问当期类的成员方法。

    public void printfDate() {
        System.out.println(this.year+"/"+this.month+"/"+this.day);
        this.show();//通过this.来进行访问
    }
    
    public void show() {
        System.out.println("this访问了show");
    }

========================================================================================================

对于第二个问题:为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?
解决这个问题,我们需要了解new关键字背后,JVM做了哪些事情。这方便比较深,有兴趣的朋友可以自己去研究一下,这里由于篇幅原因不再细说。(其实我也不知道

总结

this引用

  1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
  2. this只能在"成员方法"中使用
  3. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象
  4. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法
    对象的引用传递给该成员方法,this负责来接收

构造方法

  1. 名字必须与类名相同
  2. 没有返回值类型,设置为void也不行
  3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
  4. 构造方法可以重载
  5. 一旦用户定义,编译器则不再生成。
  6. 通过this引用访问构造方法,必须是构造方法中第一条语句,并且不能形成环。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值