[ Java学习基础 ] Java构造函数
构造方法是类中特殊方法,用来初始化类的实例变量,它在创建对象(new运算符)之后自动调用。
Java构造方法的特点如下:
-
构造方法名必须与类名相同。
-
构造方法没有任何返回值,包括void。
-
构造方法只能与new运算符结合使用。
示例代码如下:
1 //Rectangle.java文件 2 package com.a51work6; 3 4 // 矩形类 5 public class Rectangle { 6 7 // 矩形宽度 8 int width; 9 // 矩形高度 10 int height; 11 // 矩形面积 12 int area; 13 14 // 构造方法 15 public Rectangle(int w, int h) { 16 width = w; 17 height = h; 18 area = getArea(w, h); 19 } 20 ... 21 }
代码第15行是声明了一个构造方法,其中有两个参数w和h,用来初始化Rectangle对象的两个成员变量width和height,注意前面没有任何的返回值。
默认构造方法
有时在类中根本看不到任何的构造方法。例如本节中User类代码如下:
1 //User.java文件 2 package com.a51work6; 3 4 public class User { 5 6 // 用户名 7 private String username; 8 9 // 用户密码 10 private String password; 11 12 }
从上述User类代码,只有两个成员变量,看不到任何的构造方法,但是还是可以调用无参数的构造方法创建User对象,因为Java虚拟机会为没有构造方法的类,提供一个无参数的默认构造方法,默认构造方法其方法体内无任何语句,默认构造方法相当于如下代码:
//默认构造方法 public User() { }
默认构造方法的方法体内无任何语句,也就不能够初始化成员变量了,那么这些成员变量就会使用默认值,成员变量默认值是与数据类型有关。
构造方法重载
在一个类中可以有多个构造方法,它们具体有相同的名字(与类名相同),参数列表不同,所以它们之间一定是重载关系。
构造方法重载示例代码如下:
1 //Person.java文件 2 package com.a51work6; 3 4 import java.util.Date; 5 6 public class Person { 7 8 // 名字 9 private String name; 10 // 年龄 11 private int age; 12 // 出生日期 13 private Date birthDate; 14 15 public Person(String n, int a, Date d) { 16 name = n; 17 age = a; 18 birthDate = d; 19 } 20 21 public Person(String n, int a) { 22 name = n; 23 age = a; 24 } 25 26 public Person(String n, Date d) { 27 name = n; 28 age = 30; 29 birthDate = d; 30 } 31 32 public Person(String n) { 33 name = n; 34 age = 30; 35 } 36 37 public String getInfo() { 38 StringBuilder sb = new StringBuilder(); 39 sb.append("名字: ").append(name).append('\n'); 40 sb.append("年龄: ").append(age).append('\n'); 41 sb.append("出生日期: ").append(birthDate).append('\n'); 42 return sb.toString(); 43 } 44 }
上述代码Person类代码提供了4个重载的构造方法,如果有准确的姓名、年龄和出生日期信息,则可以选用代码第15行的构造方法创建Person对象;如果只有姓名和年龄信息则可选用代码第21行的构造方法创建Person对象;如果只有姓名和出生日期信息则可选用代码第26行的构造方法创建Person对象;如果只有姓名信息则可选用代码第32行的构造方法创建Person对象。
Tips:如果在类中添加了带参的构造函数,系统就不会在自动生成无参的构造函数,所以建议添加带参数的构造函数后,再手动添加一个默认无参的构造函数。
构造方法封装
构造方法也可以进行封装,访问级别与普通方法一样,构造方法的访问级别参考[ Java学习基础 ] Java的封装性与访问控制中图所示。示例代码如下:
1 //Person.java文件 2 package com.a51work6; 3 4 import java.util.Date; 5 6 public class Person { 7 8 // 名字 9 private String name; 10 // 年龄 11 private int age; 12 // 出生日期 13 private Date birthDate; 14 15 // 公有级别限制 16 public Person(String n, int a, Date d) { 17 name = n; 18 age = a; 19 birthDate = d; 20 } 21 22 // 默认级别限制 23 Person(String n, int a) { 24 name = n; 25 age = a; 26 } 27 28 // 保护级别限制 29 protected Person(String n, Date d) { 30 name = n; 31 age = 30; 32 birthDate = d; 33 } 34 35 // 私有级别限制 36 private Person(String n) { 37 name = n; 38 age = 30; 39 } 40 41 ... 42 }
上述代码第16行是声明公有级别的构造方法。代码第23行是声明默认级别,默认级别只能在同一个包中访问。代码第29行是保护级别的构造方法,该构造方法在同一包中与默认级别相同,在不同包中可以被子类继承。代码第36行是私有级别构造方法,该构造方法只能在当前类中使用,不允许在外边访问,私有构造方法可以应用于单例设计模式等设计。
----------------------------------------------------------------------------
初始化块和构造函数的执行顺序
读者可先自行阅读下面代码,判断输出结果:
1 class B extends Object 2 { 3 static 4 { 5 System.out.println("Load B"); 6 } 7 public B() 8 { 9 System.out.println("Create B"); 10 } 11 } 12 class A extends B 13 { 14 static 15 { 16 System.out.println("Load A"); 17 } 18 public A() 19 { 20 System.out.println("Create A"); 21 } 22 } 23 24 public class Testclass 25 { 26 public static void main(String [] args) 27 { 28 new A(); 29 } 30 }
输出结果:
Load B
Load A
Create B
Create A
初始化块在构造器执行之前执行,类初始化阶段先执行最顶层父类的静态初始化块,依次向下执行,最后执行当前类的静态初始化块;创建对象时,先调调用顶层父类的构造方法,依次向下执行,最后调用本类的构造方法 。所以执行顺序为:父类静态代码 -> 子类静态代码块 -> 父类构造代码块 -> 父类构造函数 -> 子类构造代码块 -> 子类构造函数