关于Java 数组内存分派一点熟悉

    添加时间:2013-5-17 点击量:

            可能Java 数组大师都很熟悉,比来我碰到了一个关于Java 数组内存分派的题目。


            呵呵。忽然就发明很多书上“根蒂根基数据类型存储在栈内存傍边,对象则保存在堆内存”这句话美满是错误的。下面是个简单的例子代码:




    public class Test {
    
    public static void main(String[] argv) {
    // 静态初始化数组
    String[] names = { Michael, Orson, Andrew };
    // 动态初始化数组
    String[] animal = new String[4];
    // 让animal 指向 namens 数组所引用的数组
    names = animal;

    System.out.println(names.length);
    System.out.println(animal.length);
    }
    }




              “Java 数组大小是不克不及改变的”这可能大师都听过,那上方这段代码就有题目了,animal [] 长度为4,而names [] 数组的长度只有3,然则经过一个赋值语句,两个数组的大小就都变为4了。这不是改变了数组的大小吗? 题目就如许挡在面前了!好吧,问问技巧进步前辈吧,就如许对数组的存储体式格式有了全新的熟悉。下面是我的一点懂得:(若是有错误的,正好被大神你看到了,也请你可以或许指出来。)


              上方的的 names 和 animal 不代表这个数组对象,而仅仅是数组的变量罢了,和C里面的指针是一样的,如许的变量叫做引用变量。数组对象是保存在堆内存傍边,大小当然是不克不及改变的,然则数组变量却可以或许指向其他的数组对象,可以看看下面这个图:


          



             蓝虚线是赋值语句 names = animal; 之前 names 和 animal 数组变量指向的堆内存傍边数组对象;


             红线是是赋值语句 names = animal;之后 names 和 animal 数组变量都同时指向一个数组对象。当然这时辰 Java 垃圾收受接管机制这时辰就会发明那个没人引用的数组对象然后把它带走。


             从上方还可以看到,“Michael”,Orson,Andrew 这些都是根蒂根基的数据类型吧。然则他们却存储在堆内存傍边。  


            实际上应当如许说:局部变量放在栈内存傍边,(像上方的 names[],animal[] 这种引用类型的变量,还有一些根蒂根基类型的变量),但应用变量所引用的对象是保存是堆内存傍边的。(包含数组还有一些我们通俗写的通俗的类对象)


            Java在堆内存傍边的对象凡是是不容许直接接见的,但你可以想到直接接见的结果。为了接见堆内存傍边的对象,这时辰就须要引用变量这个中介。


            什么时辰Java存储在栈内存中的变量是仅仅是引用变量? 什么时辰它又换了身份变为货真价实的JAVA对象纳?嗯,看看下面这个例子:


      



        public class Animal {
    
    private String name;
    private int age;

    Animal(String name,
    int age) {
    this.name = name;
    this.age = age;
    }

    public void info() {
    System.out.println(name
    + + age);
    }
    }
    public class Test {

    public static void main(String[] argv) {
    // 动态初始化数组
    Animal[] animal = new Animal[2];
    Animal cat
    = new Animal(cat, 1);
    Animal dog
    = new Animal(dog, 2);
    animal[
    0] = dog;
    animal[
    1] = cat;

    // 当数组变量引用对象的办法(或者属性)的时辰,它就变为实际的Java 对象
    System.out.println(animal.length);
    //dog 这个底本存储在栈内存傍边的对象引用经由过程调用对象的办法变为实际的对象
    dog.info();
    animal[0].info();
    }
    }


           只有当栈内存中的引用变量调用了对象的办法或者是指向了对象的属性的时辰,它就从变量真正成了对象了。(比如上方例子中的 cat,dog 对象引用变量,animal[]数组变量)。


           经由过程


            animal[0] = dog;
    
    animal[
    1] = cat;

    使得两个变量都指向了存储在堆内存傍边的对象,所以他们俩个打印出来的信息是一模一样的。


    上图中蓝线是赋值语句:

            animal[0] = dog;
    
    animal[1] = cat;
    之前的变量指向的状况,红虚线是赋值语句之后的状况,animal[0]和dog ,animal[1] 和cat 所指向的都是雷同的堆内存空间。

    (PS:我还是要感激这几个月来那几个口试官对我从头到尾的虐,固然如今练习的工作还没有个准信,当我发明我要走的路还很长很长,上方这个题目的原由也是一个口试官的提问,“你知道Java 傍边数组是如何存储的吗?”)

    我所有的自负皆来自我的自卑,所有的英雄气概都来自于我的软弱。嘴里振振有词是因为心里满是怀疑,深情是因为痛恨自己无情。这世界没有一件事情是虚空而生的,站在光里,背后就会有阴影,这深夜里一片寂静,是因为你还没有听见声音。—— 马良《坦白书》
    分享到: