java把内存划分为两种:一种是栈(stack)内存,一种是堆(heap)内存
堆内存:当在一段代码块定义一个变量时,java就在栈中为这个变量分配内存空间
栈内存:用来存放由new创建的对象和数组,在堆中分配的内存
String两种实例化方式:
1.直接赋值 2.通过构造方法完成
String str1 =“abc”;
String str2 = new String("abc");
1. 直接赋值
直接赋值可以节省内存
String str1 =“abc”;表示一个堆内存指向给了栈内存。
步骤:
- 栈中开辟一块空间存放引用变量str1。
- 到字符串常量池查找栈中有没有存放"abc", 如果有,直接令str 指向"abc";如果没有String池中开辟一块空间,存放String常量”abc”。
- 引用str1指向池中String常量”abc”。
jvm(java virtual machine)会自动根据栈中数据的实际情况来决定是否有必要创建新的对象。
字符串常量池 String pool
只存储字符串常量,字符串唯一的。
2. new()
String str2 = new String("hello"); //创建String对象 每调用一次就会创建一个新的对象
步骤:
- 栈中开辟一块空间存放引用str2
- 堆中开辟一块空间存放一个新建的String对象“hello”
- 引用str2指向堆中的新建的String对象”hello”
字符串的比较
比较类里面的数值是否相等时,用equals()方法
当测试两个包装类的引用是否指向同一个对象时,用 ==
11. 分析下面代码的结果(A)。(选择一项)
public static void main(String args[]) { String s = "abc"; String ss = "abc"; String s3 = "abc" + "def"; // 此处编译器做了优化! String s4 = "abcdef"; String s5 = ss + "def"; String s2 = new String("abc"); System.out.println(s == ss); System.out.println(s3 == s4); System.out.println(s4 == s5); System.out.println(s4.equals(s5)); }
A true true false true
B. true true true false
C. true false true true
D. false true false true
分析:
s == ss
栈中分别开辟一块空间存放引用s和ss,s和ss指向池中String常量“abc”,s和ss所指代的地址即常量“abc”所指向的地址。
输出:true
s3 == s4
栈中分别开辟一块空间存放引用s3和s4,根据编译器合并已知量的优化功能,池中开辟一块空间,存放合并后的String常量”abcdefg” ,s4所指即池中常量“abcdefg”
输出:true
s4 == s5
ss指向池中String常量“abc”,堆中开辟一块空间存放一个新建的String对象“def”,
栈中开辟一块中间存放引用s5, ss+"def" 通过StringBuilder的最后一步toString()方法还原一个新的String对象”abcdef”,因此堆中开辟一块空间存放此对象,s5指向新的String对象,s4指向池中String常量“abcdefg”,s4和s5所指向的地址不同
常量:先进行拼接,然后再常量池中找。找到了直接给地址值;找不到开辟空间再赋值;
变量:直接进行拼接,然后赋值,再将地址值传给main方法中的引用
输出:false
s4.equals(s5)
s4的值与s5的值的比对,一致
输出:true
拓展:
System.out.println(s == s2);
s2值在栈内存中,s值在堆内存中
输出:false
字符串的不可改变性
String中 null与 “ ”的区别
java中NULL与" "的区别 - hanruyue - 博客园 (cnblogs.com)
2.
分析如下Java代码,该程序编译后的运行结果是(
AD )。(选择一项)public static void main(String[ ] args) {
String str=null; //null是未分配堆内存空间 str.concat("abc"); concat将指定的字符串连接到该字符串的末尾 str.concat("def"); System.out.println(str);}
NULL代表声明了一个空对象,根本就不是一个字符串。
""代表声明了一个对象实例,这个对象实例的值是一个长度为0的空字符串
null是空对象 ""是空字符串String s=null;//null是未分配堆内存空间 String a;//分配了一个内存空间,没存入任何对象 String a="";//分配了一个内存空间,存了一个字符串对象String str="aaa"; //于栈上分配内存 String str=new String("aaa"); //于堆上分配内存A
null
B.
abcdef
C.
编译错误
D.
运行时出现NullPointerException异常
4.
以下关于StringBuffer类的代码的执行结果是(
CD )。(选择一项)public class TestStringBuffer {
public static void main(String args[]) {
StringBuffer a = new StringBuffer("A"); //假设a指向了内存地址为4000的地方
StringBuffer b = new StringBuffer("B"); //假设b指向了内存地址为5000的地方
mb_operate(a, b); //这个方法只是把a和b的地址传了过去
// x指向4000,y指向5000,a与b还是指向原来的地址。
System.out.println(a + "." + b);
}
static void mb_operate(StringBuffer x, StringBuffer y) {
x.append(y); // x:”AB” y:“B“ //这句将a指向地址的内容变了。
y = x; //只是将y指向的地址发生变化,变为4000,而main程序中的b还指向5000
}
}
A.
A.B
B.
A.A
C.
AB.AB
D.
AB.B
9.
分析下面的Java程序,编译运行后的输出结果是( B )。(选择一项)
public class Example {
String str = new String("good"); // 堆中开辟存放”good”的空间
char[] ch = { 'a', 'b', 'c' };
public static void main(String args[]) {
Example ex = new Example( );
ex.change(ex.str, ex.ch); //ex.str 堆中
System.out.print(ex.str + "and");
System.out.print(ex.ch);
}
public void change(String str, char ch[]) {
str = "test ok"; // 栈中常量池开辟空间存放”test ok” 赋给栈中的str
ch[0] = 'g'; //传的是地址码
}
}
A
goodandabc
B.
goodandgbc
C.
test okandabc
D.
test okandgbc