Java变量声明与使用时的内存分配机制

前言

考虑如下代码:

//: xin/greglee/demo/Demo.java
public class Demo {
	public static void main(String[] args) {
		// test1
		int a = 6;
		int b = a;
		b = 77;
		System.out.println(a);
		// test2
		Node node1 = new Node(6);
		Node node2 = node1;
		node2.data = 77;
		System.out.println(node1.data);
	}
}
class Node {
	int data;
	public Node(int data) {
		this.data = data;
	}
}/*output:
6
77
*///:~

test1与test2进行了相似的过程,但为何得到的结果却截然相反呢?希望在阅读本文后,读者能够找到问题的答案。

JVM中的堆和栈

堆(heap)

用于存放所有的Java对象。

栈(stack)

用于存放基本类型的数据和对象的引用。

变量的声明与使用

基本类型

Java中的基本类型有8种:boolean、char、byte、short、int、long、float、double(注意:String是对象,不是基本类型)。
声明一个基本类型的变量时,会在栈中为该变量分配一块内存,当对其初始化和赋值时,可以简单的理解为将值存储在这块内存中。
注:事实并非如此,这样描述是为了简化理解,但这样理解通常不会得到错误的结果,如果读者感兴趣,可自行查阅JVM相关资料。

对象

声明
声明一个对象类型的变量时,同样会在栈中为该变量分配一块内存,不同的是:这块内存用来存储一个对象的引用
赋值
当使用new关键字创建一个对象,会在堆中分配空间来存储此对象,通过赋值号 “=” 可以将new关键字创建出的对象的引用存储在相应对象类型的变量中。
当使用赋值号将一个对象类型的变量赋值给另一个变量时,由于该变量存储的是一个对象的引用,因此实际上是将引用赋值给了另一个变量。此时,可以简单的描述为:这两个变量引用了同一个对象。
调用
当使用英文句点(.)通过一个对象类型的变量调用其引用对象的成员时,首先通过该变量存储的引用找到其引用的对象,然后再从此对象中找到相应的成员。
tips:关于对象的引用和对象的关系,可以理解为遥控器和电视机的关系:遥控器是引用,引用的是电视机,你可以通过控制遥控器来控制电视机。

回到问题

对于test1,使用了两个基本类型的变量a、b,两个变量各有一块内存存储它的值。因此改变b的值并不会影响a的值,故输出6。
对于test2,使用了两个对象类型的变量node1、node2,两个变量各有一块内存来存储一个对象的引用。
Node node1 = new Node(6) 创建了一个Node对象,将其data值初始化为6,并将该对象的引用赋值给node1。
Node node2 = node1 将node1存储的引用赋值给了node2,也就是说,node2和node1引用了同一个对象
node2.data = 77 通过node2存储的引用找到其引用的对象、访问该对象的成员data,并将77赋值给该对象的成员data。
System.out.println(node1.data) 输出node1引用的对象的成员data的值,由于node1和node2引用的是同一个对象,而上面已经通过node2将该对象的成员data的值赋值为77,因此输出77。

你可能感兴趣的:(Java基础)