java在内存编译代码 java在内存编译代码中的应用( 五 )


String a = "ab";
String bb = "b";
String b = "a" + bb;
System.out.println((a == b)); //result = false
分析:JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a" + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b 。所以上面程序的结果也就为false 。
String a = "ab";
final String bb = "b";
String b = "a" + bb;
System.out.println((a == b)); //result = true
分析:和[3]中唯一不同的是bb字符串加了final修饰 , 对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量 池中或嵌入到它的字节码流中 。所以此时的"a" + bb和"a" + "b"效果是一样的 。故上面程序的结果为true 。
String a = "ab";
final String bb = getBB();
String b = "a" + bb;
System.out.println((a == b)); //result = false
private static String getBB() {
return "b";
}
分析:JVM对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为b,故上面 程序的结果为false 。
通过上面4个例子可以得出得知:
Strings="a" + "b" + "c";
就等价于String s = "abc";
Stringa="a";
Stringb="b";
Stringc="c";
Strings=a+b+c;
这个就不一样了 , 最终结果等于:
StringBuffer temp = new StringBuffer();
temp.append(a).append(b).append(c);
String s = temp.toString();
由上面的分析结果 , 可就不难推断出String 采用连接运算符(+)效率低下原因分析,形如这样的代码:
public class Test {
public static void main(String args[]) {
String s = null;
for(int i = 0; i100; i++) {
s += "a";
}
}
}
每做一次 + 就产生个StringBuilder对象,然后append后就扔掉 。下次循环再到达时重新产生个StringBuilder对象 , 然后 append 字符串,如此循环直至结束 。如果我们直接采用 StringBuilder 对象进行 append 的话 , 我们可以节省 N - 1 次创建和销毁对象的时间 。所以对于在循环中要进行字符串连接的应用,一般都是用StringBuffer或StringBulider对象来进行 append操作 。
String对象的intern方法理解和分析:
public class Test4 {
private static String a = "ab";
public static void main(String[] args){
String s1 = "a";
String s2 = "b";
String s = s1 + s2;
System.out.println(s == a);//false
System.out.println(s.intern() == a);//true
}
}
这里用到Java里面是一个常量池的问题 。对于s1+s2操作,其实是在堆里面重新创建了一个新的对象,s保存的是这个新对象在堆空间的的内容,所 以s与a的值是不相等的 。而当调用s.intern()方法,却可以返回s在常量池中的地址值,因为a的值存储在常量池中,故s.intern和a的值相等 。
总结
栈中用来存放一些原始数据类型的局部变量数据和对象的引用(String,数组.对象等等)但不存放对象内容
堆中存放使用new关键字创建的对象.
字符串是一个特殊包装类,其引用是存放在栈里的,而对象内容必须根据创建方式不同定(常量池和堆).有的是编译期就已经创建好,存放在字符串常 量池中,而有的是运行时才被创建.使用new关键字,存放在堆中
java程序是在编译的时候分配空间的吗,如果不是那程序在什么时候给变量分配内存空间?编译的时候是不会分配空间的,只是将java代码编译成字节码 。是在运行这段代码的时候才会分配 。javac XX.java是编译代码 , java XX时候是运行代码 。举个简单的例子:

推荐阅读