最近看书。
对于java来说,一切对象的创建都是在堆空间里,而在栈空间进行引用但是对于特殊的基本类型来说,它是在栈空间直接赋值并进行操作,所以对于int i=23;这样的语言可以解释为:
     1。栈空间里面要求对类型的生命周期有明确指定,所以必须在int类型初始化
     2。这也正好对应拉java的后期绑定的机制,因为要对小数值的基本类型进行更加行之有效的操作,所以把他放在栈空间,而在栈空间,自然不能应用到后期绑定,也就是说int类型的对象也一样是在堆空间创建。而在栈空间只是一个指针直接操作。我的疑问是,对于
     Integer i=new Integer(23);
     这个语句的理解是不是说先在栈空间进行整数int=23的初始化,然后又在堆空间创建一个Integer类型(是否在堆空间也划分拉值为23的内存空间?),再在栈空间对堆空间的Integer进行引用(如果是以上,为什么一开始直接在堆空间划分空间就好拉?还要多一步在栈空间的操作?)。这样进行   
     栈空间操作-》堆空间操作-》栈空间引用    不是有点感觉多此一举么?因为在栈空间划分拉内存,又在堆空间又划分一块值一样的内存。
     而对于字符串 string="fejaio" 直接进行初始化这样,它是在栈空间进行的么,但是它不属于基本类型啊?
     又对于String s=new String("fejaio") 这里创建的2个对象:pool对象和heap对象。那么最初的pool对象根据一切对象都在堆空间内,那么是不是说常量池也是在堆空间里的呢?那何必再创建一个heap对象,它本身不就是heap对象喽?而如果常量池不是在堆空间里,那么所谓的pool对象不是跟一切对象都在堆空间里相冲突?

解决方案 »

  1.   

    基本类型不是对象,这是java本身规定的,所以int是不是在堆空间去的
    fejaio" 直接进行初始化这样,它是在栈空间进行的么,但是它不属于基本类型啊? 
    我的理解是一堆的字符,但我觉得 string="fejaio"  中的"fejaio" 是在堆中
      

  2.   

    基本类型不是对象,int不是在堆空间
      

  3.   

    对于第一个问题,我倾向于认为jvm不会先在栈空间开辟一块内存来存储23,而是直接在堆空间创建对象;
    对于第二个问题,java中的String类型比较特殊,String string="fejaio";JVM会先定义一个名为string的String类的对象引用变量,然后在栈中查找有没有存放值为"fejaio"的地址,如果没有,则开辟一个存放字面值为"fejaio"的地址,接着创建一个新的String类的对象string。
    对于第三个问题,String s=new String("fejaio")这是一定会在堆中创建对象,与fejaio是否在栈空间中就没有关系了
      

  4.   

    不清楚lz问题的答案,
    不过测起来很简单嘛,把jvm的栈和堆内存都设合理一点,然后生成大量数据,看看是栈溢出还是堆溢出不就行了
    认为是堆,就把堆设小点,栈设大点,
    认为是栈,就把栈设小点,堆设大点。
    实践出真知撒
      

  5.   

    对象都是在堆空间,但是对于基本类型,那是在栈空间进行操作的。所以我觉得创建一个基本类型的封装对象,不知道在栈空间里面有没有进行内存操作
    对于第二个问题,我是不是可以认为String是在栈空间开辟,并给值,而在堆空间创建对象,那堆空间创建对象,是不是还要重复开辟内存给值呢
      

  6.   

    栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。 Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。 栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。 栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义: 
    int a = 3; 
    int b = 3; 
    编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。 这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。 要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。 String是一个特殊的包装类数据。可以用: 
    String str = new String("abc"); 
    String str = "abc"; 
    两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。 比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。 
    String str1 = "abc"; 
    String str2 = "abc"; 
    System.out.println(str1==str2); //true 
    可以看出str1和str2是指向同一个对象的。 
    String str1 =new String ("abc"); 
    String str2 =new String ("abc"); 
    System.out.println(str1==str2); // false 
    用new的方式是生成不同的对象。每一次生成一个。 因此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。 另一方面, 要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象。 由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。
      

  7.   


            栈      ┊               堆
    ┈┈┈┈┈┈┈┈┊┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
    ┌─────┐  ┊  ┌────────────┐
    │Integer i ┼───┼→    new Integer       │
    └─────┘  ┊  ├────────────┤
                    ┊  │ private int value = 23;│
                    ┊  │                        │
                    ┊  └────────────┘
    ┌─────┐  ┊
    │int i = 23│  ┊
    └─────┘  ┊
                    ┊
      

  8.   

    借宝地问个问题:
    int[] a={1,2,3,4}
    这个a是放在堆中还是在栈中?
    int[] b=new int[5];这个b又是放在哪里?
      

  9.   

    都是在堆中。
    一个array怎么能在栈中呢。
      

  10.   


          StringPool      ┊         栈        ┊                 堆
    ┈┈┈┈┈┈┈┈┈┈┈┊┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
       ┌──────┐   ┊   ┌─────┐  ┊
       │"fejaio"  ←┼────┼ String t │  ┊
       ├──────┤   ┊   └─────┘  ┊
       ├──────┤   ┊   ┌─────┐  ┊  ┌───────────────┐
       ├──────┤   ┊   │ String s ┼───┼→        new String          │
       ├──────┤   ┊   └─────┘  ┊  ├───────────────┤
       ├──────┤   ┊                   ┊  │private char[] value = {      │
       ├──────┤   ┊                   ┊  │  'f', 'e', 'j', 'a', 'i', 'o'│
       ┊  ......    ┊   ┊                   ┊  │};                            │
                          ┊                   ┊  └───────────────┘
                          ┊                   ┊
      

  11.   

    上面对应:String t = "fejaio";
    String s = new String("fejaio");
      

  12.   

    这个图画的挺好,对应拉
    String str1 =new String ("abc");
    String str2 =new String ("abc");
    既如上有共同的pool对象"abc",但被复制到堆空间2次,创建拉2个String,在这里想问下,这个常量池是位于哪里?
      

  13.   

    接上面的,从这个图我认为
    String t = "fejaio";
    String s = new String("fejaio");
    这里是两步:
       1:栈指针指向pool里面的pool对象"fejaio"
       2:栈指针指向堆空间里面的String对象
       3: 堆空间里面存放的String对象复制于pool里面的pool对象。并且是以char[]的形式(在这里,对应8楼的
      “字面常量在栈空间存值,在堆空间创建对象,但不会重复开辟内存,只是定义一个对象引用指向栈空间的字面常量”
       这一句我有不同看法,既然是复制pool里面的对象到堆里面,所谓复制,应该是把值也复制过来吧。既然有值,难道在堆里面没有再次开辟内存么?)
      

  14.   

    对于
    String t = "fejaio";
    我想拉想,觉得由上面这句,好象可以推断pool是位于栈空间的,进一步来说,常量池是位于栈空间 
    ,主要是觉得:
      :有明确的数据大小
      那么,是不是说栈空间里面包含拉常量池这样
      

  15.   

    从图来讲:我觉得大概如下- -
    |------------|      |__________|
    |栈空间——————>|          |
    |   |        |      | 堆空间   |
    |   V        |      |          |
    |-------|    |      |__________|
    |常量池 |    |
    |       |    |
    |-------|    |
    |            |
    |------------| 
      

  16.   

    具体的情况比较复杂,如果楼主想彻底的弄清楚,建议看看《Java语言规范》和《JVM规范》。
      

  17.   

    package com.test;    
       
    public class StringTest {    
       
        public static void main(String[] args)    
        {    
            //有关字符串new 的解释:new String("abc"),首先会在String pool中查找值为"abc"的字符串,如果没有找到,则将在String pool中创建一个对象,然后在String堆中创建一个对象,此时,共产生了两个对象,分别指向不同的内存地址(String pool 和 String 堆)    
            //如果在String pool中找到有"abc"这个值存在,则不会再在String pool中创建对象,而只在String堆中创建对象    
            //此时s指向的是String堆中的对象,也就是String堆中的值为"abc"的对象的引用,s的值也就是String堆中的值为"abc"的对象的内存地址    
            String s = new String("abc");    
                
            //s1指向的是String pool中值为"abc"的对象,s1的值也就是String pool中的值为"abc"的对象的内存地址    
            //此时因为String pool中值为"abc"的对象已经在上面的String s = new String("abc");步骤中被创建了,所以此时并没有创建对象    
            String s1 = "abc";    
                
            //s2指向的是在String堆中新创建的值为"abc"的对象    
            //此时也就创建了一个对象(String堆中的值为"abc"的对象,因为String pool中值为"abc"的对象已经在上面的String s = new String("abc");步骤中被创建了)    
            String s2 = new String("abc");    
                
                
            //==比较的永远是两个对象的内存地址    
            //s、s1、s2都指向的是不同的内存地址对应的对象    
            System.out.println(s == s1);//false    
            System.out.println(s == s2);//false    
            System.out.println(s1 == s2);//false    
                
                
            //String的intern()函数返回的是String pool中对应的对象    
            //s.intern()返回的是String pool中值为"abc"的对象,而s是指向String堆中的值为"abc"的对象,所以他们的内存地址肯定不同    
            System.out.println(s == s.intern());//false    
            System.out.println(s1 == s1.intern());//true    
            System.out.println(s.intern() == s2.intern());//true    
                
            String hello = "hello";    
            String hel = "hel";    
            String lo = "lo";    
                
            //原型字符串用"+"连接,过程是:字符串连接后("hello"),再去String pool中查找    
            System.out.println(hello == "hel" + "lo");//true    
            //原型字符串与字符串对象用"+"连接,过程是:字符串连接后("hello"),在String堆中创建一个新的对象,用于存放这个字符串    
            System.out.println(hello == "hel" + lo);//false    
                
        }    
    }   
      

  18.   

     public static void main(String[] args) { String s = new String("abc");//执行到这一行时,创建了几个对象? String s1 = "abc";//执行到这一行时,创建了几个对象? String s2 = new String("abc");//执行到这一行时,创建了几个对象? System.out.println(s == s1);//输出结果是什么? System.out.println(s == s2);//输出结果是什么? System.out.println(s2 == s1);//输出结果是什么? } public static void main(String[] args)<br/>{ <br/> String s = new String("abc");//执行到这一行时,创建了几个对象?<br/> String s1 = "abc";//执行到这一行时,创建了几个对象?<br/> String s2 = new String("abc");//执行到这一行时,创建了几个对象?<br/><br/> System.out.println(s == s1);//输出结果是什么?<br/> System.out.println(s == s2);//输出结果是什么?<br/> System.out.println(s2 == s1);//输出结果是什么?<br/>}<br/> 
    答案依次为: 
    2个对象 没有对象 1个对象 
    false false false 
    试题详解: 
    1.String s = new String("abc")执行此句时,首先在String Pool(String池)中查找有没有字符常量"abc",没有则在String Pool中创建"abc"的对象,当执行new String("abc")时则在java的堆中创建一个"abc"对象,而s则是该对象的引用,因此共计创建2个对象。 
    2.String s1 = "abc"执行此句时,首先还是在String Pool中查找有没有字符串常量"abc",有则直接将s1作为String Pool中"abc"的一个引用,因此此时没有创建任何对象。 
    3.String s2 = new String("abc")执行此句时,依旧在String Pool中查找有没有字符串常量"abc",有则不进行再次创建,由于这里用了new关键字(有new就有对象),所有便在java堆中又创建了一个"abc"对象(地址与第一句在堆中创建的地址不同),而s2则是这个对象的引用,因此执行此句时只创建了1个对象。 
    4.我们知道"=="是判断对象的,因此由于s指向的是java对中的"abc"对象而s1指向的则是String Pool中的"abc"对象,所以输出false。 
    5.6判断同上。  
     今天刚在JAVA贴吧找到的一个很不错的帖子,你可以看看,偶看明白了~
      

  19.   

    差不多也明白拉。还有点疑问,就是从常量池复制到堆中,在堆是不是真的没有分配内存,而只是指向拉String pool里的对象
      

  20.   

    我也看得明白拉- -,只是里面的String s = new String("abc"),也说是把pool里面的对象复制到堆空间里,所以用创建是不是不太合适,从这里来看,还是不明白把pool对象复制到堆空间里面作为一个String对象的时候到底有没有重新划分内存。还是只是一个指针引用pool对象。但是如果只是引用,那么String s = new String("abc")就不能说有2个对象拉吧(因为堆里的对象只是一个指针引用pool对象啊)。所以我觉得还是划分拉内存用来保存从pool复制过来的pool对象的,大家说呢
      

  21.   

    为什么不直接打开源码看看呢    public String(String original) {
    int size = original.count;
    char[] originalValue = original.value;
    char[] v;
       if (originalValue.length > size) {
          // The array representing the String is bigger than the new
          // String itself.  Perhaps this constructor is being called
          // in order to trim the baggage, so make a copy of the array.
                int off = original.offset;
                v = Arrays.copyOfRange(originalValue, off, off+size);
      } else {
          // The array representing the String is the same
          // size as the String, so no point in making a copy.
        v = originalValue;
      }
    this.offset = 0;
    this.count = size;
    this.value = v;
        }
      

  22.   

    v = Arrays.copyOfRange(originalValue, off, off+size);垃圾驴 嵌套都看不懂 还号称中国最大
      

  23.   

    int 不是对象,要用这种数据来做为对象的话,就要把这些基本的数据类型转换为包装类数据
    对应的为:
    int --Integer;
    String --String ;
    float--Float;
    double--Double;
    ^…………
      

  24.   

    不是说int是对象,比如String="xx"的时候,在栈空间的常量池里有个String pool对象,值为xx.
      

  25.   

    String不是基本类型,是不可变类
    不可变类的对象是不能被改变的
    JAVA资料太多?选中想收藏的文字(图片),右键选“收录到易载”,搞定!
      

  26.   

    基本类型不是对象,int不是在堆空间