HeadFirstJava——9_构造器与垃圾收集器

一、构造器

1 堆与栈

内存中有两种区域:堆heap和栈stack;

其中,堆,又可垃圾回收的堆,存放所有对象;栈存放方法调用和局部变量;

2 实例变量和局部变量

实例变量是被声明在类中方法之外的变量,而不是在方法中,存在所属的对象中;

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

// 每个Duck对象都会有独立的size
public class Duck{
	int size;
}

局部变量被声明在方法或方法的参数中,是暂时的,生命周期只限于方法被放在栈上的这段时期;

局部变量没有默认值;

// 参数x和变量i, b都是局部变量
public void foo(int x){
	int i = x + 3;
	boolean b = true;
}

3 方法

当调用一个方法时,该方法会放在调用栈的栈顶;

栈顶上的方法是目前正在执行的方法;

若foo()方法调用bar()方法,则bar()方法会放在foo()方法上面;

4 对象引用

若局部变量是对对象的引用,则局部变量本身放在栈上,对象本身放在堆上;

若实例变量是对对象的引用,则实例变量和对象都在堆上;

5 构造函数

Duck myDuck = new Duck();

上例中,看似在调用Duck()方法,但其实是调用Duck的构造函数。

5.1 概念

构造函数不是方法,因为方法有返回类型,构造函数没有返回类型;

构造函数的函数名一定与类的名称相同;

构造函数不会被继承;

默认构造函数没有参数;

在初始化一个对象时执行,即在构造函数外调用构造函数的方法只有新建一个类;

若没有编写构造函数,编译器会帮忙编写一个构造函数;

5.2 对象状态的初始化

使用无参数的构造函数;

public class Duck{
	int size;
	public Duck(){
	}
	public void setSize(int theSize){
		size = theSize;
	}
}

public class DuckTest{
	public static void main(String[] args){
		Duck duck = new Duck();
		duck.setSize(3);
	}
}

使用有参数的构造函数;

public class Duck{
	int size;
	public Duck(int duckSize){
		size = duckSize;
	}
}

public class DuckTest{
	public static void main(String[] args){
		Duck duck = new Duck(25);
	}
}

注意:在编写构造函数时,一定要有没有参数的构造函数;因为编译器只会在没有设定构造函数时才会调用,若编写一个有参数的构造函数,且需要一个没有参数的构造函数,则必须手动编写!

5.3 重载构造函数

必须保证参数的类型和顺序不同,编译器不看参数的名称;

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

6 父类、继承与构造函数的关系

6.1 父类的构造函数在对象的生命中扮演的角色

在创建新对象时,所有继承下来的构造函数都会执行,即每个父类都有一个构造函数,且每个构造函数都会在子类对象创建时执行;

抽象类也有构造函数,只是不能对其进行new操作,但抽象类可以是父类,因此其构造函数会在具体子类创建时执行;

6.2 调用父类构造函数

在构造函数中,用super()调用父类的构造函数;

注意:父类的部分必须在子类创建完成之前就必须完整的成型,即先执行父类的构造函数,再执行子类的构造函数;

// 通过
public Boop(){
	super();
}

//通过
public Boop(int i){
	super();
	size = i;
}

// 通过,编译器自动将super()加到最前面
public Boop(){
}

// 通过
public Boop(int i){
	size = i;
}

// 编译不通过
public Boop(int i){
	size = i;
	super();
}

6.3 有参数的父类构造函数

public abstract class Animal{
	// 每个Animal都会有名字
	private String name;
	
	// Hippo会继承这个getter
	public String getName(){
		return name;
	}
	
	// 有参数的构造函数,用以设定name
	public Animal(String theName){
		name = theName;
	}
}

public class Hippo extends Animal{
	public Hippo(String name){
		// 传给Animal的构造函数
		super(name);
	}
}

public class HippoTest{
	public static void main(String[] args){
		Hippo h = new Hippo("Buffy");
		System.out.println(h.getName());
	}
}

6.4 调用重载版本

使用this()从某个构造函数调用同一个类的另一个构造函数;

this()只能用在构造函数中,且必须是第一行语句;

每个构造函数可选择调用super()或this(),但不能同时调用;

class Mini extends Car{
	Color color;
	
	// 无参数的构造函数以默认的颜色调用真正的构造函数
	public Mini(){
		this(Color.Red);
	}
	
	// 真正的构造函数
	public Mini(Color c){
		super("Mini");
		color = c;
	}
	
	// 编译不通过,一个构造函数不能同时调用this()和super()
	public Mini(int size){
		this(Color.Red);
		super(size);
	}
}


二、垃圾收集器

1 对象的生命周期

1.1 

局部变量只会在声明该变量的方法中;

实例变量的寿命与对象相同,若对象还活着,则实例变量也会活着;

1.2

引用变量只能在处于它的范围中才能被引用,即除非引用变量是在它的范围中,不然就不能使用对象的遥控器;

只要有活着的引用,对象也就会活着;

当最后一个引用消失时,对象就会变成可回收的。

2 释放对象的引用的方法

2.1 引用永久性的离开它的范围

void go(){
	Life z = new Life();
}

2.2 引用被赋值到其它的对象上

Life z = new Life();
z = new Life();

2.3 直接将引用设定为null

Life z = new Life();
z = null;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值