java数组及内存分配

概念

java提供的数组是用来存储固定大小,相同类型的元素的。

基本使用方法

public class ArrayTest {
            
       /**
        * 一维数组的使用
        */
       @Test
       public void array1test() {
           // 数组的定义,java在定义数组时并不为数组元素分配内存,因此[]中无需指明数组长度
           int intArray1[];
           int[] intArray2;
              
           // 如果要为数组分配空间,需要用到new操作符
           intArray1 = new int[5];
              
           // 数组的初始化 
           // 1.静态初始化,即声明数组的同时进行初始化
           int intArray3[] = {1,2,3,4}; 
           // 2.动态初始化,先声明数组,之后再进行初始化
           int intArray4[] = new int[5];
           intArray4[0] = 1;
           intArray4[1] = 2;
           intArray4[2] = 3;
           intArray4[3] = 4;
           intArray4[4] = 5;
              
           // 数组的引用,采用数组名加下标的方法,下标从0开始,每个数组都有一个length属性来表明数组的长度
           System.out.println("intArray4[0]: " + intArray4[0]);
           System.out.println("length of intArray4:" + intArray4.length);
             
           // 数组的遍历
           // 1. for循环
           for(int i=0; i<intArray4.length; i++)
               System.out.println("intArray4[" + i + "]:" + intArray4[i]);
               
           // 2. 增强的for循环,也称为foreach循环
           for(int var : intArray4)
               System.out.println("  " + var);
           }
       
       /**
        * 二维数组的使用
       */
       @Test
       public void array2Test(){
            /**
             * 二维数组,可以看做是数组的数组,空间是不连续的,所以不要求二维数组每一维大小相同
            */
              
            // 数组的声明
            int intArray5[][] = {{1,2},{2,3},{1,3}};
            int intArray6[][] = new int[2][3];
             
            int intArray7[][] = {{1,2},{1,2,3},{1,2,3,4}};
            
            int intArray8[][] = new int[3][];
            intArray8[0] = new int[2];
            intArray8[1] = new int[3];              
        }

数组的内存分配

一维数组的内存分配情况

public class ArrayTest {
        /**
         * java数组必须经过初始化才能使用,而数组一旦初始化该数组所占的内存空间,数组长度都是不可变的。
         */
        
        /**
         * 一维数组的内存分配情况
         */
        @Test
        public void array3Test(){
            // 静态初始化,初始化元素的个数决定了数组大小
            int array0[] = {1,2,3,4,5};
            System.out.println("array0地址: " + array0);
            for(int i=0; i<array0.length; i++){
                 System.out.println("array0[" + i + "]: " + array0[i]);
            }
            // 动态初始化,需要给出数组的大小
            int array1[] = new int[6];
            System.out.println("array1地址: " + array1);
            for(int i=0; i<array0.length; i++){
                 System.out.println("array1[" + i + "]: " + array1[i]);
            }
              
            array0 = array1;
            System.out.println("现在array0的地址是: " + array0);                          
        }      
}

运行结果:
array0地址: [I@e285c6
array0[0]: 1
array0[1]: 2
array0[2]: 3
array0[3]: 4
array0[4]: 5
array1地址: [I@1be5d1
array1[0]: 0
array1[1]: 0
array1[2]: 0
array1[3]: 0
array1[4]: 0
现在array0的地址是: [I@1be5d1

  • 从程序中运行中可以看出,采用静态初始化数组array0时,首先在栈内存中分配一个指向堆内存的地址,然后再堆中分配一段连续的内存空间,保存初始化数据,由此可见,采用静态初始化时,不用指定数组大小,程序会根据初始化数组自动识别数组大小。

  • 采用动态初始化时,需要先指定数组大小,程序自动将堆中的数组初始化为默认数值,int类型,自动初始化为0.

    Java内存对象访问定位0.png
  • 当运行程序array0 = array1时,就是将array0指定array1指向堆内存中的地址,此时array0和array1指向了同样的地址,array0之前指向的地址变成了垃圾。


    Java内存对象访问定位1.jpg

二维数组的内存分配情况

package jdk.collection;

import org.junit.Test;

public class ArrayTest {
       /**
         * 二维数组的内存分配情况
         */
        @Test
        public void array4Test(){
            // 不指定二维
            int array2[][] = new int[3][];
            System.out.println("array2地址:" + array2);
            for(int i=0; i<array2.length; i++)
                 System.out.println("array2[" + i + "]:" + array2[i]);
               
            // 指定二维
            int array3[][] = new int[3][2];
            System.out.println("array3地址: " + array3);
            for(int i=0; i<array3.length; i++)
                 System.out.println("array3[" + i + "]:" + array3[i]);
            
            System.out.println("array3[2][1] = " + array3[2][1]);
               
            array3[1] = array3[0];
            array3[2] = new int[3];
            for(int i=0; i<array3.length; i++)
                 System.out.println("array3[" + i + "]:" + array3[i]);
        }

运行结果:

array2地址:[[I@e285c6
array2[0]:null
array2[1]:null
array2[2]:null
array3地址: [[I@1be5d1
array3[0]:[I@13fd745
array3[1]:[I@1327b79
array3[2]:[I@12410ac
array3[2][1] = 0
array3[0]:[I@13fd745
array3[1]:[I@13fd745
array3[2]:[I@2c41f4

  • 从程序运行结果可以看出,当不指定二维大小时,int array2[][] = new int[3][]创建了一个指向3个地址的地址,并且3个地址指向null;而int array3[][] = new int[3][2]创建了一个指向3个地址的地址,并且这3个地址分别指向了3个初始化为0的内存空间。
Java内存对象访问定位2.jpg

java二维数组实际上是指向地址的地址,因而array3[1] = array3[0]; array3[2] = new int[3]表明,array3[1]指向了array3[0]的地址,而array3[2]指向了一个新的含有3个int类型的地址。

Java内存对象访问定位3.png

存放对象类型的数组

首先定义一个Person类

package jdk.collection;

public class Person {
    private String name;
    private int age;
    
    public Person(){};
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
//  public String toString(){
//      return "name: " + name + "   age:" + age;
//  }
}

定义存放Person对象的数组

package jdk.collection;

import org.junit.Test;

public class ArrayTest {
       @Test
        public void array5Test(){
            
            Person array4[];
//          System.out.println("array4地址:" + array4); // 编译不过去
            array4 = new Person[3];
            System.out.println("array4地址:" + array4);
            
            //直接进行初始化
            Person array5[] = {new Person("张三",16),new Person("李四",20)};
            System.out.println("array5地址:" + array5);
            for(int i=0; i<array5.length; i++){
                System.out.println("array5[" + i + "]地址:" + array5[i]);
                System.out.println("array5[" + i + "].getname:" + array5[i].toString());
            }
            
            // 先声明再初始化
            Person array6[] = new Person[3];
            for(int i=0; i<array6.length; i++){
//              System.out.println("初始化前array6[" + i + "]地址:" + array6[i]);
//              System.out.println("初始化前array6[" + i + "]内容:" + array6[i].toString());
            }
            
            Person per0 = new Person("王五",17);
            Person per1 = new Person("周六",18);
            array6[0] = per0;
            array6[1] = per1;
//          for(int i=0; i<array6.length; i++){
            for(int i=0; i<2; i++){
                System.out.println("赋值后array6[" + i + "]地址:" + array6[i]);
                System.out.println("赋值后array6[" + i + "]内容:" + array6[i].toString());
            }
            System.out.println("per0地址:" + per0 + "   per1地址:" + per1);
            
        }

运行结果
array4地址:[Ljdk.collection.Person;@e285c6
array5地址:[Ljdk.collection.Person;@1be5d1
array5[0]地址:jdk.collection.Person@13fd745
array5[0].getname:jdk.collection.Person@13fd745
array5[1]地址:jdk.collection.Person@1327b79
array5[1].getname:jdk.collection.Person@1327b79
赋值后array6[0]地址:jdk.collection.Person@12410ac
赋值后array6[0]内容:jdk.collection.Person@12410ac
赋值后array6[1]地址:jdk.collection.Person@2c41f4
赋值后array6[1]内容:jdk.collection.Person@2c41f4
per0地址:jdk.collection.Person@12410ac per1地址:jdk.collection.Person@2c41f4

可以类比二维数组,存放对象类型的一维数组,就是定义了一个指向数组,该数组指向存放对象的地址。
Person array4[];仅仅声明了array4是一个指向Person对象的数组,并没有为其分配地址,只有在new之后才为其分配了。

Java内存对象访问定位4.png

Person array5[] = {new Person("张三",16),new Person("李四",20)}定义了一个指向2个Person类型数组的引用,而Person array6[] = new Person[3]仅仅定义了一个指向3个person类型数组的引用,数组并没有初始化,因而无法知道数组指向的地址。


Java内存对象访问定位5 (1).png

而对array6进行复制之后,其内存分配情况如图所示,与array5相比较,多了2个单独指向person的引用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容