Java类与对象的地址空间分析

    在进入正题之前,先说一些相关的知识。大家都知道Java除了8种基本的数据类型就只有引用类型,也就是说类属于应用类型,我们操作类的时候实际上就是操作类的地址空间,而这一切的实现过程就是引用。下面我将通过举一个例子详细分析程序运行过程中类地址空间的变化。

public class Computer {
	String brand;
	float price;
	
	public Computer(String brand, float price) {
		super();
		this.brand = brand;
		this.price = price;
	}
	
	public Computer() {
	}

	public void playgame(){
		System.out.println(" use"+brand+"computer play game");
	}
}

public class Student {
	String name;
	int age;
	String id;
	String grade;
	String sex;
	Computer computer;
	public Student(String name, int age, String id, String grade, String sex, Computer computer) {
		super();
		this.name = name;
		this.age = age;
		this.id = id;
		this.grade = grade;
		this.sex = sex;
		this.computer = computer;
	}
	public Student() {
		super();
	}
	
	public void study(){
		System.out.println(name+" is studying.");
	}

}

public class TestObject {
	public static void main(String[] args) {
		Student student=new Student();
		Computer c=new Computer("联想",4999);
		student.name="perry";
		student.age=18;
		student.computer=c;
		student.study();
		System.out.println(student.computer.brand);
		c.brand="华硕";
		System.out.println(student.computer.brand);
	}

}

    以上代码有三个类,其中Student类持有Computer类的对象,而TestObject类则是用来测试上面那两个类,下面我将逐句分析main方法里面代码所引起的内存空间的变化。过程图如下所示:


首先说明一下,以下所说的过程均在字节码文件中发生,但我们无法看懂字节码文件,所以通过代码来分析。进入正题,编译器编译完成之后,代码开始执行。先从main入口方法开始,第一行代码为Student student=new Student();,在运行到Sudent时,JVM(虚拟机)便开始在方法区寻找Student类的信息,但程序中是第一次使用Student类,所以方法区中没有该类的信息,接着JVM便会使用类加载器加载该类。接着运行到student,运行到这里之后会在栈中生成一个变量,这个变量指向后面创建的对象。new Student()则是以加载的Student类为模板在堆中创建一个对象,这里用的是空构造方法,所以对象的所有属性均是默认值,这个对象便是student变量指向的对象,需要注意的是变量指向的是对象的首地址,再声明一下图中使用的地址均是随意捏造的,实际运行中只知引用地址为4个字节长,所以无需注意这个。回归正传,运行第二句Computer c=new Computer("联想",4999);,这一句也是创建对象,过程与第一句大同小异,就不重复解释了。第三句student.name="perry";,首先解释一下,在加载类的信息完之后,所有的常量。声明一下,字符串也是常量,并且在本次测试中常量只有字符串。在执行第三句的时候便是将student的name属性指向TestObject类常量池中的“perry”常量。第四局是student.age=18; 这一句因为age属性为基本类型,所以直接赋值为18,。第五句是student.computer=c; 这一句将student对象的属性computer指向之前通过第二句在堆上建立的Computer类的对象,这样变量c和student.computer指向了相同的对象即相同的地址。第六句是执行study()方法,Java在建立对象的时候并不会再次建立方法,而只是将方法指向方法区中类的方法。

    最后三句是为了做一个测试,

System.out.println(student.computer.brand);//这一句输出结果大家都知道,结果是:联想

c.brand="华硕";

System.out.println(student.computer.brand);//那么这一句呢?有些同学便会觉得还是联想,事实是华硕.前文分析第五句的时候已经说过,变量c和student.computer指向了相同的对象即相同的地址,而c.brand="华硕";本质上是改变c变量指向地址所在对象的属性,即执行这一句过后堆中的Computer类的对象的属性已经改变,所以student.computer指向的便是已经改变的Computer类的对象,故最后输出的是"华硕"。

    最后再补充一下,方法区中并不会出现相同的常量,不同类中的常量池有一套共享机制,所以不同类中出现相同的常量时,后者会引用前者而不会再次生成。另外,理解对象需要牢记,操作对象实际上是操作内存地址














猜你喜欢

转载自blog.csdn.net/huangyilinnuli/article/details/79433322