构造器 :
也叫构造方法(constructor),用于对象的初始化。构造器是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。构造器的名称应与类的名称一致。Java通过new关键字来调用构造器,从而返回该类的实例,是一种特殊的方法。
放在最前面的图片:
构造函数的关健特征:会在对象能够被赋值给引用之前就执行!
1.新建Duck状态的初始化
class Duck{
int size;
public Duck(){ //构造函数
System.out.println("Quack");
}
public void setSize(int newSize){
size = newsize;
}
}
public class UserADuck{
public static void main(String[] args){
Douck d = new Duck(); //Duck在此处已经建立,开始去调用构造函数,但是却没有size的值
d.setSize(42); //我们必须在此处设立size的值
}
}
2.使用构造函数来初始化Duck状态
class Duck{
int size;
public Duck(int duckSize){ //有参构造函数
System.out.println("Quack");
size = newsize;
}
}
public class UserADuck{
public static void main(String[] args){
Douck d = new Duck(42); //传值给构造函数
}
}
3.关于有参构造器和无参构造器
class Point {
double x, y; //全局变量
//如果不添加有参构造器,系统默认构造无参构造器
public Point(double x, double y) { //局部变量
this.x = x; //this表示创建好的对象
this.y = y;
}
public double getDistance(Point p) {
return Math.sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
}
}
public class TestConstructor {
public static void main(String[] args) {
Point p = new Point(3.0, 4.0); //调用构造器
Point origin = new Point(0.0, 0.0);
System.out.println(p.getDistance(origin));
}
}
4.构造函数的要点:
1. 通过new关键字调用
2. 构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造器里使用return返回某个值。
3. 如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数。如果已定义则编译器不会自动添加!
4. 构造器的方法名必须和类名一致!
5. 构造函数的重载
(重载的方法,实际是完全不同的方法,只是名称相同而已! )
构成方法重载的条件:
1.不同的含义:形参类型、形参个数、形参顺序不同
2.只有返回值不同不构成方法的重载
构造方法也是方法,只不过有特殊的作用而已。与普通方法一样,构造方法也可以重载
public class User {
int id; // id
String name; // 账户名
String pwd; // 密码
//无参构造
public User() {
}
//有参构造
public User(int id, String name) {
super();
this.id = id;
this.name = name;
}
//有参构造
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public static void main(String[] args) {
User u1 = new User();
User u2 = new User(1563231, "小明");
User u3 = new User(56891, "小红", "123456");
}
}
6.调用父类构造函数
在创建对象时,所有继承下来的构造函数都会被执行!即每个父类的构造函数都会在子类对象创建时期执行。即使是抽象类也有构造函数,虽然我们不能对抽象类执行new操作,但是抽象类也是父类,因此它的构造函数会在子类创建出实例时执行。
在构造函数中,我们用super调用父类的构造函数的部分,这一路会调用到Object的构造函数为止,一路执行,然后逐个弹出。子类可能会根据父类的状态(实例变量)来继承方法,完整的对象需要完整的父类核心,所以必须执行父类的构造函数,来读取父类的实例变量,继而来继承父类的部分方法。
public class Animal {
public Animal(){
System.out.println("Making an animal.....");
}
}
---------------------------------------------------------
public class Hippo extends Animal{
public Hippo(){
System.out.println("Making a Hippo.....");
}
}
----------------------------------------------------------
public class main {
public static void main(String[] args) {
System.out.println("Staring....");
Hippo h =new Hippo();
}
}
--------------------------------------------------------
输出: Staring....
Making an animal.....
Making a Hippo...
内存编译过程:(如果对Java内存不了解的,可参考:内存管理)
这里我们为什么没有用到super呢?
1.如果你编写构造函数时,没有调用super,编译器会帮你自动加上super()的调用;
2.如果说你没有编写构造函数,但需要引用父类构造函数时,我们需要自行加入super();来调用父类构造函数。
7.调用有参数的父类构造函数
这里通过super();来引用父类,把name的值传进去,让Animal把它存到私有的name实例变量中,继而才可以调用getName方法
public class Animal {
private String name;
public String getName(){
return name;
}
public Animal(String theName){
name = theName;
}
}
---------------------------------------------
public class Hippo extends Animal{
public Hippo(String name){
super(name); //传给Animal的构造函数
}
}
----------------------------------------------
public class main {
public static void main(String[] args) {
System.out.println("Staring....");
Hippo h =new Hippo("Buffy"); //创建Hippo,传入name
System.out.println(h.getName());
}
}
----------------------------------------------
输出:Buffy
8.调用super()和this()
this()的应用场景:如果说我们有某个重载版的构造函数,除了不能处理不同类型的参数之外,可以处理所有的工作,那么我们为了实现代码的易维护性,我们想让所有的构造函数都先去调用这个构造函数,然后由它来执行真正的构造函数。这时候我们就要用到this();
注意:
super()和this()两者只会出现在第一行,而且同一个构造方法不能同时出现super()和this()