读后有收获可以支付宝请作者喝咖啡
在创建实例的时候,我们经常需要同时初始化这个实例的字段,例如:
Person ming = new Person();
ming.setName("小明");
ming.setAge(12);
初始化一个对象实例需要3行代码,如果忘记调用()或(),则实例内部的状态不正确。
创建对象实例时,是否可以将所有内部字段初始化为合适的值?
没错。
此时,我们需要一个构造函数。
创建实例时,实例实际上是通过构造函数初始化的。我们先定义一个构造函数,在创建实例的时候可以同时传入name和age来完成初始化:
// 构造方法
----
public class Main {
public static void main(String[] args) {
Person p = new Person("Xiao Ming", 15);
System.out.println(p.getName());
System.out.println(p.getAge());
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
}
因为构造函数很特别,所以构造函数的名字就是类名。构造函数的参数没有限制,方法内部可以写任意语句。但是,与普通方法相比,构造函数没有返回值(也没有 void)。要调用构造函数,必须使用 new 运算符。
默认构造函数
任何类都有构造函数吗?是的。
那我们之前没有给类写构造函数,为什么可以调用new()?
原因是如果一个类没有定义构造函数,编译器会自动为我们生成一个默认构造函数,它没有参数,也没有执行语句,像这样:
class Person {
public Person() {
}
}
需要注意的是,如果我们自定义构造函数,编译器将不再自动创建默认构造函数:
// 构造方法
----
public class Main {
public static void main(String[] args) {
Person p = new Person(); // 编译错误:找不到这个构造方法
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
}
如果你希望能够使用带参数的构造函数方法,但又想保持不带参数的构造函数,你只能定义两个构造函数:
// 构造方法
----
public class Main {
public static void main(String[] args) {
Person p1 = new Person("Xiao Ming", 15); // 既可以调用带参数的构造方法
Person p2 = new Person(); // 也可以调用无参数构造方法
}
}
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
}
在构造函数中未初始化字段时,引用类型字段默认值为null,值类型字段默认值为0,int类型默认值为0,默认值为类型为假:
class Person {
private String name; // 默认初始化为null
private int age; // 默认初始化为0
public Person() {
}
}
也可以直接初始化字段:
class Person {
private String name = "Unamed";
private int age = 10;
}
那么问题来了:既要初始化字段方法,又要在构造函数中初始化字段:
class Person {
private String name = "Unamed";
private int age = 10;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
我们在创建对象的时候,通过new("小明",12)得到的对象实例,该字段的初始值是多少?
在Java中,当一个对象实例被创建时,它会按以下顺序初始化:
先初始化字段,例如int age = 10;表示该字段初始化为 10, ;表示该字段默认初始化为0,name;表示引用类型字段默认初始化为null;
执行构造函数的代码进行初始化。
所以构造函数的代码是后面运行的,所以new("小明", 12)的字段值最终是由构造函数的代码决定的。
多个构造函数
可以定义多个构造函数。当被new操作符调用时,编译器会自动根据构造函数的参数个数、位置和类型来区分它们:
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this.name = name;
this.age = 12;
}
public Person() {
}
}
如果调用new("小明",20);,会自动匹配构造函数(,int)。
如果调用new("小明");,会自动匹配构造函数()。
如果调用new();,会自动匹配构造函数()。
一个构造函数可以调用其他构造函数以便于代码重用。调用其他构造函数的语法是 this(...):
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this(name, 18); // 调用另一个构造方法Person(String, int)
}
public Person() {
this("Unnamed"); // 调用另一个构造方法Person(String)
}
}
练习
请在类中添加一个 (, int) 构造函数:
public class Main {
public static void main(String[] args) {
// TODO: 给Person增加构造方法:
Person ming = new Person("小明", 12);
System.out.println(ming.getName());
System.out.println(ming.getAge());
}
}
----
class Person {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
给类添加一个 (, int) 构造函数
总结
创建实例时,会通过new操作符调用其对应的构造函数,该构造函数用于初始化实例;
当没有定义构造函数时,编译器会自动创建一个默认的无参构造函数;
可以定义多种构造方法,编译器会根据参数自动判断;
可以在另一个构造函数中调用构造函数,以便于代码重用。