构造器的引入
假设为编写的每个类都定义一个initialize()方法,这个方法提醒你在使用其对象之前,应首先调用initialize()方法,但这也意味着用户必须记得自己去调用此方法。
为此,Java通过提供构造器让类的设计者确保每个对象都会得到初始化,在创建对象时,如果其类具有构造器,Java就会在用户操作对象之前自动调用相应的构造器,从而确保初始化的进行
构造器的命名
命名有两个问题:第一,所取的任何名字都可能与类的某个成员名称相冲突;第二,调用构造器是编译器的责任,所以必须让编译器知道该调用哪个方法
为此,Java让构造器采用与类相同的名称,这样看来最简单且更符合逻辑
1 package com.constructor; 2 3 class Rock { 4 Rock(int i) { 5 System.out.println("Rock " + i + " "); 6 } 7 } 8 9 public class SimpleConstructor { 10 public static void main(String[] args) { 11 for(int i = 0; i < 5; i++) 12 { 13 new Rock(i); 14 } 15 } 16 }
结果为:
1 Rock 0 2 Rock 1 3 Rock 2 4 Rock 3 5 Rock 4
构造器的几种方式以及特点
- 无参构造器(也叫默认构造器),当类中没有任何构造器时,Java会自动给类提供一个无参构造器,若有构造器,Java就不会为类提供无参构造器,需要用户自己编写
- 有参构造器,如上述代码,Rock构造器接收一个int类型的变量,就可以在初始化对象时提供实际参数,如果Rock(int i)是类中唯一的构造器,编译器不允许用户以其他任何方式创建创建Rock对象
构造器初始化原理
代码:Person p = new Person();
- 创建一个Person类型的引用变量p
- 通过new关键字创建一个Person对象(也可以理解为将Person类实例化)
- 为Person对象里的全局变量赋初值,如int类型的变量初值为0,boolean类型的变量初值为false,String类型的变量初值为null等等
- new Person()小括号里若没有实际参数,则初始化结束,直接到第5步;若小括号里有参数,则根据参数的类型,顺序,数量,在类中查找相对应的构造器(方法重载),将实际参数传给形式参数
- 将Person对象的内存地址值复制给P引用变量,此时p指向堆内存的Person对象
扩展一
构造器中最常见的几种运用:
- 用this关键字为全局变量赋值
- 用this关键字调用构造器
- 用super关键字调用父类构造器
例一:用this关键字为全局变量赋值
1 package com.constructor; 2 3 class Person { 4 String name; 5 static int age; 6 7 Person() {} 8 9 Person(String name, int age) { 10 this.name = name; 11 this.age= age; 12 } 13 } 14 15 public class HardConstructor { 16 public static void main(String[] args) { 17 Person p1 = new Person(); 18 System.out.println("p1:name" + "---" + p1.name + " age" + "---" + p1.age); 19 Person p2 = new Person("Jhin", 21); 20 System.out.println("p2:name" + "---" + p2.name + " age" + "---" + p2.age); 21 } 22 }
结果为:
1 p1:name---null age---0 2 p2:name---Jhin age---21
例二:用this关键字调用本类构造器
1 package com.constructor; 2 3 class Person{ 4 Person() { 5 this("Jhin", 21); 6 } 7 8 Person(String name, int age) { 9 System.out.println("name:" + name + "---" + "age:" + age); 10 } 11 } 12 13 public class HardConstructor { 14 public static void main(String[] args) { 15 Person s = new Person(); 16 } 17 }
结果为:
name:Jhin---age:21
例三:用super关键字调用父类构造器
1 package com.constructor; 2 3 class Father { 4 String name; 5 static int age; 6 7 Father() { 8 System.out.println("这是父类无参构造器"); 9 } 10 11 Father(String name, int age) { 12 this.name = name; 13 this.age = age; 14 System.out.println("这是父类有参构造器"); 15 } 16 } 17 18 class Son extends Father { 19 Son() { 20 super(); 21 } 22 23 Son(String name, int age) { 24 super(name, age); 25 } 26 } 27 28 public class HardConstructor { 29 public static void main(String[] args) { 30 Son s1 = new Son(); 31 Son s2 = new Son("Jhin", 21); 32 } 33 }
结果为:
1 这是父类无参构造器 2 这是父类有参构造器
扩展二
讨论构造器是否属于静态方法?
首先,从Java语言规范对“方法”的定义来来说,构造器根本不是方法,它没有返回值。尽管new表达式确实返回了对新建对象的引用,但构造器本身并没有任何返回值
然后,构造器无法被重写无法被隐藏(若隐藏则无法创建对象,但工具类不同,它会隐藏构造器,方法全用static修饰,让用户通过类名调用方法),不参与多态
其次,静态方法中不能使用this关键字,但构造器中可以使用this关键字,this是指调用当前方法的对象,而静态方法不属于任何对象
最后,构造器只能由new关键字(或别的构造器)调用,不能通过方法调用,new表达式作为一个整体保证了对象的创建和初始化时打包在一起的,不能分开。且构造器只负责初始化,从创建对象是由new关键字本身执行的