如何初始化对象
在Java方法内部定义一个局部变量时,必须要初始化,否则会编译失败
public class Date {
public static void main(String[] args) {
int a;
System.out.println(a);
}
}
要让上述代码通过编译,非常简单,只需在正式使用a之前,给a设置一个初始值即可
而对于对象需要调用之前写的SetDate方法才可以将具体的日期设置到对象中
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.printDate();
d.setDay(2021,6,9);
d.printDate();
}
这样初始化对象可能会比较麻烦,那么有没有更好的办法初始化对象呢?
接下来就大家了解一下对象初始化的其他方法
构造方法
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次
public class Date {
public int year;
public int month;
public int day;
// 构造方法:
// 名字与类名相同,没有返回值类型,设置为void也不行
// 一般情况下使用public修饰
// 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
public Date(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
System.out.println("Date(int,int,int)方法被调用了");
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
// 此处创建了一个Date类型的对象,并没有显式调用构造方法
Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了
d.printDate(); // 2021-6-9
}
}
从上面的例子我们可以初步了解到到构造方法的特性,那构造方法还有其他哪些特性呢?
- 名字必须与类名相同
- 没有返回值类型,设置为void也不行
- 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
- 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
public class Date {
public int year;
public int month;
public int day;
// 无参构造方法
public Date(){
this.year = 1900;
this.month = 1;
this.day = 1;
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
Date d = new Date();
d.printDate();
}
}
可以看到这里就实现了方法的重载,上述两个构造方法:名字相同,参数列表不同,因此构成了方法重载
- 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的
public class Date {
public int year;
public int month;
public int day;
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
Date d = new Date();
d.printDate();
}
}
上述Date类中,没有定义任何构造方法,编译器会默认生成一个不带参数的构造方法。
注意:一旦用户定义,编译器则不再生成。
public class Date {
public int year;
public int month;
public int day;
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
// 如果编译器会生成,则生成的构造方法一定是无参的
// 则此处创建对象是可以通过编译的
// 但实际情况是:编译期报错
Date d = new Date();
d.printDate();
}
}
这里报错的原因是因为实际参数列表和形式参数列表长度不同
- 构造方法中,可以通过this调用其他构造方法来简化代码
public class Date {
public int year;
public int month;
public int day;
// 无参构造方法--内部给各个成员赋值初始值,该部分功能与三个参数的构造方法重复
// 此处可以在无参构造方法中通过this调用带有三个参数的构造方法
// 但是this(1900,1,1);必须是构造方法中第一条语句
public Date(){
this(1900, 1, 1);
//this.year = 1900;
//this.month = 1;
//this.day = 1;
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
}
注意:
this(…)必须是构造方法中第一条语句
不能形成环
public Date(){
this(1900,1,1);
}
public Date(int year, int month, int day) {
this();
}
此时就不可以调用了
- 绝大多数情况下使用public来修饰,特殊场景下会被private修饰
默认初始化
public class Date {
public int year;
public int month;
public int day;
public Date(int year, int month, int day) {
System.out.println(this.year);
System.out.println(this.month);
System.out.println(this.day);
}
public static void main(String[] args) {
Date d = new Date(2021,6,9);
}
}
在一开始我们介绍如何初始的时候a没有赋值输出编译器会报错,那么对象没有赋值为什么编译器不报错呢?
要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:
Date d = new Date(2021,6,9)
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
- 检测对象对应的类是否加载了,如果没有加载则加载
- 为对象分配内存空间
- 处理并发安全问题
- 初始化所分配的空间
即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值
就地初始化
在声明成员变量时,就直接给出了初始值。
public class Date {
public int year = 1900;
public int month = 1;
public int day = 1;
public Date() {
}
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void show(){
System.out.println(year+" "+month+" "+day);
}
public static void main(String[] args) {
Date d2 = new Date();
d2.show();
Date d1 = new Date(2021, 6, 9);
d1.show();
}
}
此时可以看见Date d2 = new Date();打印出的就是默认初始化的值而Date d1 = new Date(2021, 6, 9);打印的则是我们传递过去的值
注意:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中