用栈和堆来理解 String

java把内存划分为两种:一种是栈(stack)内存,一种是堆(heap)内存

堆内存:当在一段代码块定义一个变量时,java就在栈中为这个变量分配内存空间

栈内存:用来存放由new创建的对象和数组,在堆中分配的内存

String两种实例化方式:

        1.直接赋值 2.通过构造方法完成

String str1 =“abc”;
String str2 = new String("abc");

1. 直接赋值

直接赋值可以节省内存

String str1 =“abc”;表示一个堆内存指向给了栈内存。

步骤:

  1. 栈中开辟一块空间存放引用变量str1。
  2. 到字符串常量池查找栈中有没有存放"abc", 如果有,直接令str 指向"abc";如果没有String池中开辟一块空间,存放String常量”abc”。
  3. 引用str1指向池中String常量”abc”。

jvm(java virtual machine)会自动根据栈中数据的实际情况来决定是否有必要创建新的对象。

字符串常量池 String pool

只存储字符串常量,字符串唯一的。

2. new()

 String str2 = new String("hello");  //创建String对象   每调用一次就会创建一个新的对象

步骤:

  1. 栈中开辟一块空间存放引用str2
  2. 堆中开辟一块空间存放一个新建的String对象“hello”
  3. 引用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

字符串的不可改变性

原文链接:http://t.csdn.cn/Cblyv

String中 null与 “ ”的区别

java中NULL与" "的区别 - hanruyue - 博客园 (cnblogs.com)

2.

分析如下Java代码,该程序编译后的运行结果是(  A D )。(选择一项)

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类的代码的执行结果是(  C  D 。(选择一项)

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我来回答你的问题。 栈、和方法区都是计算机内存的一部分,用于存储程序运行时所需要的数据。 栈是一种先进后出(Last In First Out,LIFO)的数据结构,它用于存储函数的调用过程中的临时数据,比如局部变量、函数的参数等。栈的特点是空间连续、大小固定、访问速度快。当一个函数被调用时,它的参数和局部变量会被压入栈中,当函数执行完毕后,这些数据会被弹出栈。 是一种可以动态分配空间的内存池,它的大小不固定,可以根据需要动态调整。主要用于存储程序运行时动态分配的数据,比如对象、数组等。的特点是空间不连续、大小不固定、访问速度比栈慢。当一个对象被创建时,它会被分配在中,并且它的引用会被存储在栈中。 方法区是一种用于存储类的元数据信息的内存区域,它主要用于存储类的常量池、方法信息、字段信息等。方法区的特点是空间大小固定、访问速度比慢。当一个类被加载到内存中时,它的元数据信息会被存储在方法区中。 下面举一个实例来说明栈、和方法区的使用: ```java public class MemoryExample { public static void main(String[] args) { int x = 10; // x是一个局部变量,它被存储在栈中 Person p = new Person("Tom"); // p是一个对象引用,它被存储在栈中,而对象本身被存储在String s = "hello"; // s是一个字符串对象引用,它被存储在栈中,而字符串对象本身被存储在常量池中的方法区中 } } class Person { private String name; public Person(String name) { this.name = name; } } ``` 在这个例子中,变量x被存储在栈中,它的值是10。变量p是一个对象引用,它被存储在栈中,而对象本身被存储在中。变量s是一个字符串对象引用,它被存储在栈中,而字符串对象本身被存储在常量池中的方法区中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值