楼主肯定是把一些概念弄混了……
在JVM概念上,有Java方法调用栈这么一种东西。每调用一个方法就会建立一个新的栈帧,放在方法调用栈的栈顶。
这个栈里所能直接容纳的数据包括:
1) 所有Java原始类型,即boolean、char、byte、short、int、long、float、double。
2) returnAddress类型。这个是JVM内部使用的数据类型而不是对Java程序可见的类型,用于表示Java方法的跳转地址。2)与1)一起,构成了JVM所支持的原始类型。
3) 引用类型。在JVM中,一个引用类型数据可以是指向一个类实例、数组或者接口的引用。
上面的1)和2)都好理解,其中2)对Java程序不可见,下面就忽略它。在Java方法里使用原始类型的局部变量时,它们就是分配在Java方法调用栈的栈帧上的(具体说是分配在栈帧的局部变量区里)。
但3)相对前两者就显得不同。Java的所有对象的实际数据的空间都是在Java堆上分配的,但引用类型的局部变量的空间则是在栈帧上分配的。这是怎么回事呢?
假设有下面一段代码:public class Foo {
public void bar() {
Object a = new Object();
}
}
则“a”是一个引用类型的局部变量,它本身是在栈帧上分配空间的;而它所指向的对象,也就是new出来的那个Object的实际数据所占的空间则是在Java堆上分配的。也就是说一定要分清楚,“引用”也是数据,“对象”也是数据;“引用”的数据就是为了指向对象而用的(我在极力避免使用“指针”这个词,不过如果这个词更容易理解的话就用这个词来理解吧……)。
又例如这样:
public class Foo {
public void bar() {
Object a = null;
}
}
此时a仍然是一个引用类型的局部变量,与前一个例子一样,需要在栈帧上分配空间。但这次它的初始值是一个特殊的值null,也就是说a现在没有指向任何对象。即便它没有指向任何对象,它仍然是有效的数据,需要占据空间。
作为局部变量使用的原始类型与引用类型的变量都是在栈帧上分配空间的;而作为对象的成员或者是数组的成员的数据都是在栈上分配空间的,无论是原始类型还是引用类型(的引用)。
public class Foo {
private static int i; // 静态变量在方法区里分配空间
private static final int CONST_VALUE = 2; // 常量在常量池分配空间
private int j; // 成员变量随对象在堆上分配空间
private String s; // 作为成员变量的引用类型的引用,也随着对象在堆上分配空间
public void bar() {
Object a; // 作为局部变量的引用类型的引用,在栈上分配空间
int b; // 局部变量的原始类型变量,在栈上分配空间
}
}
art_codes 写道
因为int等等不能.出来呀……
没错,Java里的原始类型数据都不是对象。
需要更详细的解释的话,自己好好读读Java入门资料就能找到的~
2009年4月25日 03:03