Java与内存
Java的内存分为4大块:heapsegment,stack segment,code segment,data segment
分别是:堆,栈,代码区,静态区。
堆:所有通过new出来的对象都放在堆中。
栈:基本数据类型,引用
代码区:程序的方法都放在这儿
静态区:静态变量都放在这儿
另外,在.class文件中,会对文件中的常量存放在常量池和静态常量池中(这两个池都在.class中)。也就是说,在程序中出现“abc”这个常量,在编译成.class文件时,就已经存放在常量池中了。
问:String s=new String("abc");中创建了几个对象?
答:两个,一个匿名对象,内容为abc。另一个通过new形式创建。
原因:API String中有如下语句:Java 程序中的所有字符串字面值(如 "abc")都作为此类的实例实现。
再次:根据Stringtemp="abc";
String s=newString(temp);
你可以更清楚的看出到底产生了几个对象。
问:String s="a"+"b"+"c";中创建了几个对象?
答:产生了四个对象,三个匿名的String对象,一个匿名的StringBuilder对象。
依据:String的API:Java语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或StringBuffer)类及其 append 方法实现的。
解释:上面这条语句等价于:
String s=newSringBuilder("a").append("b").append("c").toString();其中"a","b","c"都是匿名的对象,至于为什么,请查看今天的第一个知识点(Java与内存)。
问:如下程序中,输出结果分别是什么?
public classTest1{
publicstatic void main(String[] args){
Test1 t=new Test1();
Aa=new A();
a.m=1;
t.f2(a);
System.out.println(a.m);
t.f1(a);
System.out.println(a.m);
}
publicvoid f1(A a){
a.m=2;
}
publicvoid f2(A a){
a=newA();
a.m=3;
}
}
class A{
intm;
}
控制台结果:
1
2
原因:需要注意的是,new 创建的对象在堆中,而引用是在栈中,一个引用等于另一个引用时,两个引用指向同一个堆中的对象。
上面A a=new A(); a.m=1;在堆中产生了一个A的对象,其中m的值为1;
调用f2方法,注意f2这两个字母的后面括号中的内容(A a),这意味着又创建了一个名为a的引用,但和main中的a不同,两个都叫a,但存放在栈中的位置是不同的,然后,将main中的a传入方法f2,即令f2中的a等于main中的a,两个不同的引用指向同一个堆中的对象。那么可以想象到,当在f2中改变a的引用后,方法运行完,f2中的a销毁,main中的a是不会改变的,因为它们本身就是不同的。
但是,像f1那样,虽然a不同,但是a.m,即两个引用指向的堆中的对象是同一个,改变的是同一个对象中属性的值,即使f1中的a销毁,值仍然改变了。
结论:对于调用方法但是没有返回值的情况,注意是引用改变,还是引用所指向的对象中的属性改变。
小技巧:一般调用方法时,看引用后面是等号,说明引用改变了,引用后面是点,说明对象内容改变了。