# Java构造函数看这一篇就够啦!

Java构造函数看这一篇就够啦!

Java中的对象声明

Cat myCat = new Cat();

此句话是Java中的对象声明语句。语句完成对对象的声明、创建、赋值。

①【Cat myCat = new Cat();】 加粗部分声明一个引用变量

Java虚拟机分配空间给引用变量,并且将此变量声明为myCat。并且这个引用变量被永久的固定为Cat类型。换言之,这是一种控制Cat的遥控器,而不会是控制其他类型的遥控器。

在这里插入图片描述

②【Cat myCat = new Cat();】加粗部分创建对象

此部分要求Java虚拟机分配堆空间给新建的Cat对象。

在这里插入图片描述

③【Cat myCat = new Cat();】加粗等号用于连接对象和引用

作用是把新的Cat赋值给myCat这个引用变量,换言之就是设定遥控器所控制的对象给遥控器。

在这里插入图片描述

这里接下来就要介绍一下对象的垃圾回收机制。

当Java虚拟机启动的时候,会从底层的操作系统当中取得一块空间,以此空间来执行Java程序。

所有的对象都生存在可以垃圾回收的堆上对象的方法调用和局部变量是在栈上的。对象在可

此处要区分实例变量与局部变量

实例变量声明在类当中代表独立对象的字段。

public class Duck {
    int size;  //每个Duck当中都有独立的size
}

局部变量是被声明在方法当中的。生存周期只是暂时的,只限于被放在栈上的这段时间(方法调用到执行完毕的这段时间)。

public void foo(int x) {  //参数x、i、b均为方法中申明的为局部变量
	int i = x + 3;  
	boolean b = true;
}

要注意方法是会被堆在一起成为一个栈,在栈顶上的这个方法是当前正在执行的方法。

实例变量是声明在类中方法之外的地方。局部变量声明在方法或者方法的参数上。所有的局部变量都存在于栈上相应对应的堆块中。对象引用变量于primitive主数据类型都存放在粘上。无论是实例变量还是局部变量,对象都是存储在堆上。

构造函数与方法

Cat myCat = new Cat(); 很像在调用Cat()方法 但是实际上是在调用Cat的构造函数。

要注意构造函数看上去很像是执行方法,但是并不是方法。构造函数带有new的时候会执行的程序代码,会在初始一个对象的时候执行。

构造函数带有你在初始化对象的时候会执行的程序代码,即在新建对象的时候就会被执行。即使自己没有写构造函数,编译器也会自动帮你写一个构造函数出来。

public class UseADuck {
	public static void main(String[] args) {
		Duck d = new Duck();
	}
}
public class Duck {
	public Duck() {
		System.out.println("Quack");
	}
}

问题来了,既然编译器会自动生成一个构造函数,为什么还需要自己写一个构造函数?

实际上编译器自己生成的构造函数是原始的,如果永无自己有需要程序代码初始化的变量,那么这个时候就需要有程序代码帮忙初始化。例如如果Duck对象需要有一个size需要主程序进行设定就需要新建方法。

public class Duck {
	int size;
	public Duck() {
		System.out.println("Quack");
	}
	public void setSize(int newSize) {
		size = newSize;
	}
}

public class UseADuck {
	public static void main(String[] args) {
		Duck d = new Duck();
		d.setSize(42);  
	}
}

这时候需要区分构造函数和方法。构造函数在Java中可以与类同名的方法而不会变成构造函数,差别在于是否有返回类型,构造函数不会有返回类型。

构造函数是不会被继承的。

使用构造函数初始化

一个对象的使用不应该在状态被初始化之前就使用,最好的习惯是把需要需要初始化的程序代码放在构造函数中,将构造函数设定为需要参数输入。

public class UseADuck {
	public static void main(String[] args) {
		Duck d = new Duck(42);
	}
}
public class Duck {
	int size;
	public Duck(int duckSize) {
		System.out.println("Quack");
		size = duckSize;
		System.out.println("size is " + size);
	}
}

这样在初始化对象的时候就会构造函数,注意这里构造函数是没有返回类型的,所以是构造函数,而不是与类同名的方法。这里直接将需要初始化的变量声明在构造函数当中是比较安全的做法。

这里需要说一个比较好的习惯,就是一定要有不需要参数的构造函数。当不知道duck的大小的时候,可以设置一个默认的值而不需要指定大小。因为如果没有输入值时,没有预处理初始赋值就使用默认值。

一种不太好的方法是使用一个默认参数:

public class Duck {
    int size;
    public Duck(int newSize) {
        if (newSize == 0) {
            size = 27;
        } else {
            size = newSize;
        }
    }
}

可是又存在一个问题 如果真的有一个size=0的Duck就存在一定的问题。

所以使用以下的方法进行构造:

需要使用两种的方法来创建新的Duck

public class Duck {
	int size;
    public Duck() {
        size = 27;
    }
    public Duck(int duckSize) {
    	size = duckSize;
    }
}
知道大小:
Duck d = new Duck(15);
不知道大小:
Duck d2 = new Duck();

此时使用两种构造函数就可以在调用的时候顺利的区分哪一种是无参数输入 使用的是真正的默认参数。

Duck d = new Duck(); 与 Duck d = new Duck(27); 的含义就不同了。

这里注意如果一个类有一个以上的构造函数,代表了构造函数也是重载的。

编译器不一定会帮你写出没有参数的构造函数。如果已经写了一个有参数的构造函数,并且你需要一个无参数的构造函数,那么你自己必须手动写。只要你有自己写的构造函数,无论是哪一种,就默认告诉编译器不需要帮自己写。

如果类中有一个以上的构造函数,则必须参数要不一样。

包括了参数的顺序与类型,只要有不同即可。与重载的规则相同。

public class Mushroom {
    public Mushroom(int size) { }
    public Mushroom() { }
    public Mushroom(boolean isMagic) { }
    public Mushroom(boolean isMagic, int size) { }
    public Mushroom(int size, boolean isMagic) { }
}

小结:

(1)实例变量保存在所属的对象中,位于堆上。

(2)如果实例变量是个对对象的引用,则引用与对象都是在堆上。

(3)构造函数是个会在新建对象的时候执行程序代码。(鸭子叫)

(4)构造函数必须与类同名并且没有返回类型

(5)可以使用构造函数来初始化被创建对象的状态

(6)没有写构造函数编译器会自动安排一个构造函数 默认构造函数无参数。如果你写了一个任意的构造函数,编译器就不会调用。

(7)最好使用无参数的构造函数,可以让人选择使用默认值。

(8)重载的构造函数是指让人可以选择使用默认值。

(9)重载的构造函数必须有不同的参数、两个构造函数的参数必须不同。

(10)实例变量是有默认值的,原始默认是是0 / 0.0 / false 引用的默认值是null

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值