度快,要好好利用啊!Java就把对象的引用放在栈里。为什么呢?因为引用的使用频率高吗?
不是的,因为Java在编译程序时,必须明确的知道存储在栈里的东西的生命周期,否则就没法释放旧的内存来开辟新的内存空间存放引用——空间就那么大,前浪要把后浪拍死在沙滩上啊。
现在清楚堆、栈和堆栈了吧?
三、特殊的“对象”
先来看《Java编程思想》中的一段话:
在程序设计中经常用到一系列类型,他们需要特殊对待。之所以特殊对待,是因为new将对象存储于“堆”中,故用new创建一个对象──特别小、简单的变量,往往不是很有效。因此,不用new来创建这类变量,而是创建一个并非是引用的变量,这个变量直接存储值,并置于栈中,因此更加高效。
在Java中,这些基本类型有:boolean、char、byte、short、int、long、float、double和void;还有与之对应的包装器:Boolean、Character、Byte、Short、Integer、Long、Float、Double和Void;他们之间涉及到装箱和拆箱,我们有机会再聊。
看两行简单的代码:
这两行代码在编译的时候是什么样子呢?
编译器当然是先处理int a = 3;
,不然还能跳过吗?编译器在处理int a = 3;
时在栈中创建了一个变量为a的内存空间,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。
编译器忙完了int a = 3;
,就来接着处理int b = 3;
;在创建完b的变量后,由于栈中已经有3这个字面值,就将b直接指向3的地址;就不需要再开辟新的空间了。
依据上面的概述,我们假设在定义完a与b的值后,再令a=4,此时b是等于3呢,还是4呢?
思考一下,再看答案哈。
答案揭晓:当编译器遇到a = 4;
时,它会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向4这个地址;因此a值的改变不会影响到b的值哦。
最后,留个作业吧,下面这段代码在运行时会输出什么呢?
public class Test1 {
public static void main(String args[]) {
int a = 1;
int b = 1;
a = 2;
System.out.println(a);
System.out.println(b);
TT t = new TT("T");
TT t1 = t;
t.setName("TT");
System.out.println(t.getName());
System.out.println(t1.getName());
}
}
class TT{
private String name;
public TT (String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name1) {
this.name = name1;
}
}