系列文章目录
能看懂文字就能明白系列
C语言笔记传送门
🌟 个人主页
:古德猫宁-
🌈 信念如阳光,照亮前行的每一步
文章目录
- 系列文章目录
- 🌈 *信念如阳光,照亮前行的每一步*
- 前言
- 一、this的使用
- this引用的特性
- 二、对象的构造和初始化
- 成员变量和局部变量之间的差别
- 三、如何初始化对象
- 就地初始化
- 通过构造方法初始化
- 构造方法的特性
- 构造方法的调用
- 四、默认初始化
前言
本节目标:
掌握this引用,构造方法的定义及其使用
本节重点:
都是重点
一、this的使用
先看一个例子:
public class Date {
public int year;
public int month;
public int day;
public void setDay(int y, int m, int d){
year = y;
month = m;
day = d;
}
public void printDate(){
System.out.println(year + "/" + month + "/" + day);
}
public static void main(String[] args) {
// 构造三个日期类型的对象 d1 d2 d3
Date d1 = new Date();
Date d2 = new Date();
Date d3 = new Date();
// 对d1,d2,d3的日期设置
d1.setDay(2020,9,15);
d2.setDay(2020,9,16);
d3.setDay(2020,9,17);
// 打印日期中的内容
d1.printDate();
d2.printDate();
d3.printDate();
}
}
以上代码定义了一个日期类,然后main方法中创建了三个对象,并通过Date类中的成员方法对对象进行设置和打印,代码整体逻辑非常简单,应该没有任何问题。
但是细思之下有以下两个疑问:
- 形参名不小心与成员变量相同:
public void setDay(int year, int month, int day){
year = year;
month = month;
day = day;
}
这样写的话我们可能就有这些疑问了:那函数体中到底是谁给谁赋值?成员变量给成员变量?参数给参数?参数给成员变量?成员变量参数?估计自己都搞不清楚了。
- 三个对象都在调用setDate和printDate函数,但是这两个函数中没有任何任何有关对象的说明,setDate和printDate函数如何知道打印的是哪个对象的数据呢?
接下来有请this
登场
this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成,在后面要习惯使用this。
public class Date {
public int year;
public int month;
public int day;
public void setDay(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(this.year + "/" + this.month + "/" + this.day);
}
}
public static void main(String[] args) {
Date d = new Date();
d.setDay(2023,12,28);
d.printDate();
}
注意:this引用的是调用成员方法的对象
this引用的特性
- this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
- this只能在成员方法中使用
- 在成员方法中,this只能引用当前对象,不能再引用其他对象
- this是成员方法第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员,this来负责接收(如上图所示)
二、对象的构造和初始化
成员变量和局部变量之间的差别
在Java方法内部定义一个局部变量时,局部变量必须初始化(局部变量是声明在方法中的),否则会编译失败(C语言则可以)
例如:
对于上述的代码,你可以声明没有值的a,但如果想要使用时,编译器就会报错,而想要上面的代码编译通过,只需要给变量a初始化即可
如图:
而对于成员变量,那可就不一样了,在未初始化成员变量的时候,编译器仍然可以编译运行(注意:成员变量是声明在类内而不是方法中)
这是为什么呢?后面会介绍哒
三、如何初始化对象
那到底如何初始化对象呢,在Java中,初始化对象的方法有很多种,且听小弟慢慢道来
就地初始化
顾名思义,在声明变量的时候就赋予变量的值,这跟初始化局部变量一样(在实际中,就地初始化其实比较少,除非有特殊业务需求,比如任何一次对象的实例化之后,都期望这个对象叫dada,年龄为20)
当然我们也可以借助方法来帮助我们完成初始化
通过构造方法初始化
构造方法(也称构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期只调用一次(构造方法也是定义在类内)
如图是一个带两个参数的构造方法:
如图是一个不带参数的构造方法:
上述的两个构造方法,名字相同,参数列表不同,因此构成了方法重载。
特别注意的是:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。
构造方法的特性
- 名字必须和类名相同
- 没有返回值类型,设置为void也不行
- 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
- 构造方法可以重载(用户可以根据自己的需求提供不同参数的构造方法)
重点:
如果我们没有自己定义任何一个构造方法,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
它长这样:
但是!!!!!!!
如果我们一旦写了任何一个构造方法的时候,Java就不会提供这个默认的构造方法了(救急不救穷)什么意思呢?
在上面的代码中,我们自己定义了一个构造方法,那么Java就不会提供一个无参的构造方法了,我们需要把参数传递给构造方法才不会报错
如图:
构造方法的调用
那在程序中,这些构造方法是什么时候被调用的呢?
我们用代码来检验一下
如图所示,只有在实例化对象的时候才被调用且在整个对象的生命周期内只调用一次。
在构造方法中,可以通过this调用其他构造方法来简化代码(注意是在构造方法中才可以)
在上面的代码中,可以在无参数构造方法中通过this调用带有两个参数的构造方法给成员变量初始值,特别注意的是,this(“zhangsan”,18)必须是构造 方法中的第一条语句,否则编译器会报错。
如图所示:
四、默认初始化
在开头我们讲述了局部变量和成员变量的差别,那为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?
要搞清楚这个情况,就需要知道 new 关键字背后所发生的一些事情:
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
- 检测对象对应的类是否加载了,如果没有加载则加载
- 为对象分配内存空间
- 处理并发安全问题,比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突
- 初始化所分配的空间,即:对象空间被申请之后,对象中包含的成员已经设置好了初始值,比如:
数据类型 | 默认值 |
---|---|
byte | 0 |
char | ‘\u0000’ |
short | 0 |
int | 0 |
long | 0L |
boolean | false |
float | 0.0f |
double | 0.0 |
reference | null |
- 设置对象头信息(关于对象内存模型后面会介绍)
- 调用构造方法,给对象中各个成员赋值