【Java】Java 对象的前世今生

这是一篇学习笔记。

本文会介绍对象如何创建、存在与何处、堆、栈、构造器等知识。

栈与堆:生存空间

  • 栈:存放方法调用局部变量可以被垃圾回收
  • 堆:存放对象。

当 Java 虚拟机启动时,它会从底层的操作系统中取得一块内存,并以此区段来执行 Java 程序。内存空间大小有虚拟机来决定,不同的虚拟机空间大小可能会不同。

  • 实例变量:声明在中。有默认值。生命周期与对象一样,对象不死它不死。
  • 局部变量:声明在方法中。无默认值,必须初始化。局部变量随着方法执行完毕会被销毁。
public class Test {
		int a; // 实例变量
		public void method() {
				int b = 0; // 局部变量
		}
}

方法会被堆在一起

当我们调用一个方法,这个方法会被放到栈的栈顶,方法调用完毕会被从栈顶弹出。假设栈中有两个方法 A 和 B,A 调用 B,则 B 会在 A 的上面,也就是 B 在栈顶且执行完毕先弹出去,再弹 A。

image-20201217133117283

有关对象局部变量

非 primitive 的变量只保存对象的引用而不是对象本身。不论对象是否被声明或创建,如果局部变量是个对该对象的引用,则该变量存放在栈上。再说一次,对象本身只会存在堆中

看一段代码就清楚了:

public class StackRef {
		public void foof() {
				barf();
		}
		public void barf() {
				Duck d = new Duck(24);
		}
}

image-20201217133137517

要点:

  • 对象引用变量primitive 主数据类型变量都是存在
  • 所有局部变量都存在栈上相对应的堆栈块
  • 对象本身存在

实例变量存放的地方

我们知道,局部变量是存放在栈上的,那么实例变量呢?

实例变量存放在对象所属的堆空间上,也就是说,对象的实例变量的值是存放在该对象中的。

创建对象的奇迹

我们已经知道了变量和对象的生存空间,现在可以开始深入对象的创建。声明对象和赋值有三个步骤:

  • 声明引用变量

    Duck myDuck
    
  • 创建对象

    new Duck()
    
  • 连接对象和引用

    Duck myDuck = new Duck();
    

创建对象看起来很像在调用 Duck() 方法,但其实是在调用 Duck() 的构造函数

构造函数通常伴随着 new 关键字出现,构造函数带有 new 的时候会执行的代码,换句话说,这段代码会在你初始化一个对象的时候执行。

我们没有在 Duck 里写构造函数,哪里来的呢?

其实就算你没有写,编译器会自动帮你加一个默认没有参数的构造函数:

public Duck() {
}

这跟方法很像,但**构造函数不是方法。**构造函数和方法的区别在于,前者没有返回类型,而后者有返回类型。

构造函数的一项关键特征是,它会在对象被赋值给引用之前就执行。也就是说你可以在对象被使用之前介入。比如说,你可以打印一段话:

public class Duck {
		public Duck() {
				System.out.println("芜湖~起飞~");
		}
}

或者给对象的实例变量赋值:

public class Duck {
		int size; // 实例变量
		public Duck() {
				size = 34;
		}
}

这样在 new Duck() 的时候就会执行构造函数里的代码:

image-20201217133159095

我们也可以在构造函数加上参数,用来初始化 Duck 的状态:

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

但是这样会带来一个问题:如果我不想设置 size 会怎么样?也就是说想使用无参数的构造函数。不过这里却只有一个构造函数,而且还是带参数的,所以我们必须再有一个构造函数,并且这个构造函数是无参的。如果一个类有一个以上的构造函数,这代表它们也是重载的

也就是说,一个类必须要有无参构造函数,如果你设置了一个有参数的构造函数,那么必须将无参构造函数也写出来:

public class Duck {
		int size;
		public Duck() {} // 无参构造
		public Duck(int duckSize) {  // 有参构造
				size = duckSize;
		}
}

构造函数小回顾:

  • 构造函数是在新建类时会执行的程序
  • 构造函数必须与类的名字一样,且无返回类型
  • 如果你没有写构造函数,编译器会帮你写一个没有参数的
  • 一个类可以有很多个构造函数,但不能有相同参数类型和顺序,这叫重载过的构造函数

对象的生命周期

这部分涉及到 JVM 相关知识

image-20201217133211889

参考

《Head First Java(第二版)》第九章:对象的前世今生

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值