精华内容
下载资源
问答
  • 因为 Java 数组变量是引用类型的变量,所以上述几行初始化语句执行后,三个数组在内存中分配情况如下图所 示: 由上图可知,静态初始化方式,程序员虽然没有指定数组长度,但是系统已经自动帮我们给分配了,而动态...

    对于 Java 数组的初始化,有以下两种方式,这也是面试中经常考到的经典题目:
    静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度,如:
    动态初始化:初始化时由程序员显示的指定数组的长度,由系统为数据每个元素分配初始值,如:
    因为 Java 数组变量是引用类型的变量,所以上述几行初始化语句执行后,三个数组在内存中的分配情况如下图所
    示:
    由上图可知,静态初始化方式,程序员虽然没有指定数组长度,但是系统已经自动帮我们给分配了,而动态初始化
    方式,程序员虽然没有显示的指定初始化值,但是因为 Java 数组是引用类型的变量,所以系统也为每个元素分配
    了初始化值 null ,当然不同类型的初始化值也是不一样的,假设是基本类型int类型,那么为系统分配的初始化值
    也是对应的默认值0

    展开全文
  • Java数组变量是引用类型的变量,同时因为Java是典型的静态语言,因此它的数组也是静态的,所以想要使用就必须先初始化(为数组对象的元素分配空间)。 对于Java数组的初始化,有以下两种方式: 1.静态初始化:...

    在Java中,数组变量是引用类型的变量,同时因为Java是典型的静态语言,因此它的数组也是静态的,所以想要使用就必须先初始化(为数组对象的元素分配空间)。

    对于Java数组的初始化,有以下两种方式:
    1.静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度 ,如:int[] a = {2,4,65}; 。
    2.动态初始化:初始化时由程序员显示的指定数组的长度,由系统为数据每个元素分配初始值 ,如: int[] a1 = new int[2];//动态初始化数组,先分配空间。
    总结:静态初始化方式,程序员虽然没有指定数组长度,但是系统已经自动帮我们给分配了,而动态初始化方式,程序员虽然没有显示的指定初始化值,但是因为Java数组是引用类型的变量,所以系统也为每个元素分配了初始化值null,当然不同类型的初始化值也是不一样的,假设是基本类型int类型,那么为系统分配的初始化值也是对应的默认值0。

    展开全文
  • java数组变量是引用类型的比那辆,同时应为Java是典型的静态语言,因此 他的数组也是静态的,所以想要使用就必须先初始化,有以下两种方式: 静态初始化: 初始化时有程序员显式指定每个数组元素的初始值,...

    在java中,数组变量是引用类型的比那辆,同时应为Java是典型的静态语言,因此

    他的数组也是静态的,所以想要使用就必须先初始化,有以下两种方式:

    静态初始化: 初始化时有程序员显式指定每个数组元素的初始值,由系统决定数组长度

     

    动态初始化:初始化时由程序员显式的指定数组的长度,由系统为数据每个元素分配初始值

    静态初始化方式,程序远虽然没有指定数组长度,但是系统已经自动帮我们给分配了,

    而动态初始化方式,程序员虽然没有显示的指定初始化值,但是因为Java数组是引用类型的变量,

    所以系统也为每个元素分配了初始化值Null

    当然不同类型的初始化值也是不一样的,假设是基本类型int类型,那么为系统分配的初始化值

    也是对应的默认值0

    展开全文
  • 当一个对象使用关键字“new”创建时,会堆上分配内存空间,然后返回对象的引用,这对数组来说是一样的,因为数组也是一个对象。一维数组int[] arr = new int[3];以上代码,arr变量存放了数组对象的引用;如果...

    Java中有两种类型的数组:

    基本数据类型数组;

    对象数组;

    当一个对象使用关键字“new”创建时,会在堆上分配内存空间,然后返回对象的引用,这对数组来说是一样的,因为数组也是一个对象。

    一维数组

    int[] arr = new int[3];

    在以上代码中,arr变量存放了数组对象的引用;如果你创建了一个空间大小为10的整型数组,情况是一样的,一个数组对象所占的空间在堆上被分配,然后返回其引用。

    8200d5f5f145e9363431e9ded46706c1.png

    二维数组

    那么二维数组是如何存储的呢?事实上,在Java中只有一维数组,二维数组是一个存放了数组的数组,如下代码及示意图:

    int[][] arr = new int[3][];

    arr[0] = new int[3];

    arr[1] = new int[4];

    arr[2] = new int[5];

    bae83df36464bc9d0b79e08ccd2d3fa6.png

    对于多维数组,道理是一样的。

    Java数组是静态的

    Java 语言是典型的静态语言,因此 Java 数组是静态的,即当数组被初始化之后,该数组 所占的内存空间、数组长度都是不可变的。Java 程序中的数组必须经过初始化才可使用。所谓初始化,即创建实际的数组对象,也就是在内存中为数组对象分配内存空间,并为每个数组 元素指定初始值。

    数组的初始化有以下两种方式:

    静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度。

    动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。

    不管采用哪种方式初始化Java数组,一旦初始化完成,该数组的长度就不可改变,Java语言允许通过数组的length属性来访问数组的长度。示例如下:

    public classArrayTest{public static voidmain(String[] args) {//采用静态初始化方式初始化第一个数组

    String[] books = new String[]{"1", "2", "3", "4"};//采用静态初始化的简化形式初始化第二个数组

    String[] names = {"孙悟空", "猪八戒", "白骨精"};//采用动态初始化的语法初始化第三个数组

    String[] strArr = new String[5];//访问三个数组的长度

    System.out.println("第一个数组的长度: " +books.length);

    System.out.println("第二个数组的长度: " +names.length);

    System.out.println("第三个数组的长度: " +strArr.length);

    }

    }

    上面代码声明并初始化了三个数组,这三个数组的长度将会始终不变。

    c4c7ab6d1d58d3dade24fb823b4599d5.png

    前面已经指出,Java 语言的数组变量是引用类型的变量。

    books、names 、strArr 这三个变量,以及各自引用的数组在内存中的分配示意图如图所示:

    8609763619469052d72350edf5290112.png

    从图1.1可以看出,对于静态初始化方式而言,程序员无须指定数组长度,指定该数组的 数组元素,由系统来决定该数组的长度即可。例如 books 数组,为它指定了四个数组元素,它 的长度就是4 ;对于names 数组,为它指定了三个元素,它的长度就是3 。

    执行动态初始化时,程序员只需指定数组的长度,即为每个数组元素指定所需的内存空间, 系统将负责为这些数组元素分配初始值。指定初始值时,系统将按如下规则分配初始值。

    数组元素的类型是基本类型中的整数类型(byte 、short、int 和long ),则数组元素的值是0 。

    数组元素的类型是基本类型中的浮点类型(float 、double ),则数组元素的值是0.0。

    数组元素的类型是基本类型中的字符类型(char ),则数组元素的值是'\u0000'。

    数组元素的类型是基本类型中的布尔类型(boolean),则数组元素的值是false 。

    数组元素的类型是引用类型(类、接口和数组),则数组元素的值是null 。

    Java 数组是静态的,一旦数组初始化完成,数组元素的内存空间分配即结束,程序只能改变数组元素的值,而无法改变数组的长度。

    需要指出的是,Java 的数组变量是一种引用类型的变量,数组变量并不是数组本身,它 只是指向堆内存中的数组对象。因此,可以改变一个数组变量所引用的数组,这样可以造成数 组长度可变的假象。

    假设,在上面程序的后面增加如下几行。

    public classtest{public static voidmain(String[] args) {//采用静态初始化方式初始化第一个数组

    String[] books = new String[]{"1", "2", "3", "4"};//采用静态初始化的简化形式初始化第二个数组

    String[] names = {"孙悟空", "猪八戒", "白骨精"};//采用动态初始化的语法初始化第三个数组

    String[] strArr = new String[5];//让books数组变量、strArr 数组变量指向names 所引用的数组

    books =names;

    strArr=names;

    System.out.println("--------------");

    System.out.println("books 数组的长度:" +books.length);

    System.out.println("strArr 数组的长度:" +strArr.length);//改变books 数组变量所引用的数组的第二个元素值

    books[1] = "唐僧";

    System.out.println("names 数组的第二个元素是:" + books[1]);

    System.out.println("names 数组的第二个元素是:" + strArr[1]);

    }

    }

    42494509b1a455d66be360d88d1c358d.png

    让books 数组变量、strArr 数组变量都指向names 数组变量所引 用的数组,这样做的结果就是books、strArr、names 这三个变量引用同一个数组对象。此时, 三个引用变量和数组对象在内存中的分配示意图如图 所示。

    133e51c141e07200c947974cc8cdea14.png

    从图1.2可以看出,此时 strArr、names 和books 数组变量实际上引用了同一个数组对象。

    因此,当访问 books 数组、strArr 数组的长度时,将看到输出 3。这很容易造成一个假象:books 数组的长度从4 变成了3。实际上,数组对象本身的长度并没有发生改变,只是 books 数组变 量发生了改变。books 数组变量原本指向图 1.2下面的数组,当执行了books = names;语句之后,books 数组将改为指向图1.2 中间的数组,而原来books 变量所引用的数组的长度依然是4 。

    从图1.2 还可以看出,原来 books 变量所引用的数组的长度依然是 4 ,但不再有任何引用 变量引用该数组,因此它将会变成垃圾,等着垃圾回收机制来回收。此时,程序使用books、 names 和strArr 这三个变量时,将会访问同一个数组对象,因此把 books 数组的第二个元素赋 值为“唐僧”时,names 数组的第二个元素的值也会随之改变。

    基本数据类型数组的初始化

    对于基本类型数组而言,数组元素的值直接存储在对应的数组元素中,因此基本类型 数组的初始化比较简单:

    程序直接先为数组分配内存空间,再将数组元素的值存入对应内 存里。

    下面程序采用静态初始化方式初始化了一个基本类型的数组对象。

    public classPrimitiveArrayTest{public static voidmain(String[] args) {//定义一个int[]类型的数组变量

    int[] iArr;//静态初始化数组,数组长度为4

    iArr = new int[]{2, 5, -12, 50};

    }

    }

    上面代码的执行过程代表了基本类型数组初始化的典型过程。下面将结合示意图详细介绍这段代码的执行过程。

    执行第一行代码int[] iArr;时,仅定义一个数组变量,此时内存中的存储示意图如图所示。

    02fa77f7a4022d0388d9e86c80edf39c.png

    执行了int[] iArr; 代码后,仅在 main 方法栈中定义了一个 iArr 数组变量,它是一个引用类 型的变量,并未指向任何有效的内存,没有真正指向实际的数组对象。此时还不能使用该数组 对象。

    当执行iArr = new int[]{2,5,-12,20}; 静态初始化后,系统会根据程序员指定的数组元素来决 定数组的长度。此时指定了四个数组元素,系统将创建一个长度为4 的数组对象,一旦该数组 对象创建成功,该数组的长度将不可改变,程序只能改变数组元素的值。此时内存中的存储示 意图如图所示。

    9b7995457d6489f6cf697457c0ee3327.png

    静态初始化完成后,iArr 数组变量引用的数组所占用的内存空间被固定下来,程序员只能 改变各数组元素内的值。既不能移动该数组所占用的内存空间,也不能扩大该数组对象所占用 的内存,或缩减该数组对象所占用的内存。

    所有局部变量都是放在栈内存里保存的,不管其是基本类型的变量,还 是引用类型的变量,都是存储在各自的方法栈内存中的;

    但引用类型的变量所引用的对象(包 括数组、普通的Java 对象)则总是存储在堆内存中。

    对于Java 语言而言,堆内存中的对象(不管是数组对象,还是普通的 Java 对象)通常不 允许直接访问,为了访问堆内存中的对象,通常只能通过引用变量。这也是很容易混淆的地方。 例如,iArr 本质上只是main 栈区的引用变量,但使用 iArr.length 、iArr[2] 时,系统将会自动变 为访问堆内存中的数组对象。

    对于很多Java 程序员而言,他们最容易混淆的是:引用类型的变量何时只是栈内存中的 变量本身,何时又变为引用实际的Java 对象。其实规则很简单:引用变量本质上只是一个指 针,只要程序通过引用变量访问属性,或者通过引用变量来调用方法,该引用变量就会由它所 引用的对象代替。

    public classPrimitiveArrayTest{public static voidmain(String[] args) {//定义一个int[]类型的数组变量

    int[] iArr = null;//只要不访问iArr 的属性和方法,程序完全可以使用该数组变量

    System.out.println(iArr); //①//动态初始化数组,数组长度为5

    iArr = new int[5];//只有当iArr 指向有效的数组对象后,下面才可访问iArr 的属性

    System.out.println(iArr.length); //②

    }

    }

    3bfb64b610a293a2ea76497f5e173da9.png

    上面程序中两行粗体字代码两次访问iArr 变量。

    对于①行代码而言,虽然此时的iArr 数 组变量并未引用到有效的数组对象,但程序在①行代码处并不会出现任何问题,因为此时并未 通过iArr 访问属性或调用方法,因此程序只是访问iArr 引用变量本身,并不会去访问iArr 所 引用的数组对象。

    对于②行代码而言,此时程序通过iArr 访问了length 属性,程序将自动变 为访问iArr 所引用的数组对象,这就要求iArr 必须引用一个有效的对象。

    有过一些编程经验,应该经常看到一个Runtime 异常: NullPointerException (空指针异常)。当通过引用变量来访问实例属性,或者调 用非静态方法时,如果该引用变量还未引用一个有效的对象,程序就会引发 NullPointerException 运行时异常。

    引用类型数组的初始化

    引用类型数组的数组元素依然是引用类型的,因此数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了该引用变量所引用的对象(包括数组和Java 对象)。

    为了说明引用类型数组的运行过程,下面程序先定义一个Person 类,然后定义一个 Person[]数组,并动态初始化该Person[]数组,再显式地为数组的不同数组元素指定值。该程序代码如下。

    classPerson{public intage;public doubleheight;public voidinfo(){

    System.out.println("我的年龄是:" + age + ",我的身高是:" +height);

    }

    }public classReferenceArrayTest{public static voidmain(String[] args) {//定义一个students 数组变量,其类型是Person[]

    Person[] students;//执行动态初始化

    students = new Person[2];

    System.out.println("students所引用的数组的长度是:" + students.length); //①//创建一个Person 实例,并将这个Person 实例赋给 leslie 变量

    Person leslie = newPerson();//为leslie 所引用的Person 对象的属性赋值

    leslie.age = 22;

    leslie.hight= 180;//创建一个Person 实例,并将这个Person 实例赋给lee 变量

    Person lee = newPerson();

    lee.age= 21;

    lee.hight= 178;//将leslie 变量的值赋给第一个数组元素

    students[0] =leslie;//将lee 变量的值赋给第二个数组元素

    students[1] =lee;//下面两行代码的结果完全一样,//因为lee 和students[1]指向的是同一个Person 实例

    lee.info();

    students[1].info();

    }

    }

    23fb8c13575565c6763f615dd6807bd9.png

    上面代码的执行过程代表了引用类型数组的初始化的典型过程。下面将结合示意图详细介绍这段代码的执行过程。

    执行Person[] students;代码时,这行代码仅仅在栈内存中定义了一个引用变量,也就是一个指针,这个指针并未指向任何有效的内存区。此时内存中的存储示意图如图所示。

    ce1cdd3c050c714f9c7f631dc8fd0fc6.png

    在图1.6中的栈内存中定义了一个 students 变量,它仅仅是一个空引用,并未指向任何有 效的内存,直到执行初始化,本程序对 students 数组执行动态初始化。动态初始化由系统为数 组元素分配默认的初始值null ,即每个数组元素的值都是 null 。执行动态初始化后的存储示意 图如图所示。

    79ae3fde8d36d6f4b8bc585f20c1618b.png

    从图1.7 中可以看出,students 数组的两个数组元素都是引用,而且这两个引用并未指 向任何有效的内存,因此,每个数组元素的值都是 null 。此时,程序可以通过students 来 访问它所引用的数组的属性,因此在①行代码处通过 students 访问了该数组的长度,此时 将输出2 。

    students 数组是引用类型的数组,因此 students[0] 、students[1] 两个数组元素相当于两个引 用类型的变量。如果程序只是直接输出这两个引用类型的变量,那么程序完全正常。但程序依 然不能通过students[0] 、students[1] 来调用属性或方法,因此它们还未指向任何有效的内存区, 所以这两个连续的Person 变量(students 数组的数组元素)还不能被使用。

    接着,程序定义了leslie 和lee 两个引用变量,并让它们指向堆内存中的两个Person 对象,此时的leslie、lee 两个引用变量存储在 main 方法栈区中,而两个 Person 对象则存储在堆内存中。此时的内存存储示意图如图所示。

    2a14a5d3ae831a25ec5549722a53f6dc.png

    对于leslie、lee 两个引用变量来说,它们可以指向任何有效的Person 对象,而students[0] 、 students[1] 也可以指向任何有效的Person 对象。从本质上来看,leslie、lee、students[0] 、students[1] 能够存储的内容完全相同。接着,程序执行students[0] = leslie;和students[1] = lee; 两行代码, 也就是让leslie 和students[0] 指向同一个 Person 对象,让 lee 和students[1] 指向同一个Person 对象。此时的内存存储示意图如图 所示。

    d58789f8e5c8ebb76044709261de6d7d.png

    从图1.9 中可以看出,此时 leslie 和students[0] 指向同一个内存区,而且它们都是引用类 型的变量,因此通过 leslie 和students[0] 来访问Person 实例的属性和方法的效果完全一样。不 论修改students[0] 所指向的 Person 实例的属性,还是修改 leslie 变量所指向的 Person 实例的 属性,所修改的其实是同一个内存区,所以必然互相影响。同理,lee 和students[1] 也是引用 到同一个Person 对象,也有相同的效果。

    前面已经提到,对于引用类型的数组而言,它的数组元素其实就是一个引用类型的变量, 因此可以指向任何有效的内存——此处“有效”的意思是指强类型的约束。比如,对 Person[] 类型的数组而言,它的每个数组元素都相当于Person 类型的变量,因此它的数组元素只能指 向Person 对象。

    展开全文
  • 当一个对象使用关键字“new”创建时,会堆上分配内存空间,然后返回对象的引用,这对数组来说是一样的,因为数组也是一个对象。 一维数组 int[] arr = new int[3]; 以上代码,arr变量存放了数组对象...
  • Javascript的内存分为堆内存和栈内存,数组作为对象,建立后存储内存中。 任何计算机语言内存的分配都要经历三个阶段 分配内存 对内存进行读、写 释放内存(垃圾回收) 本文主要针对数组的内存分配进行解释。...
  • Java数组在内存中如何存放的 阅读目录 一维数组 二维数组 数组对象及其引用存放在内存中的哪里? Java中有两种类型的数组: 基本数据类型数组; 对象数组; 当一个对象使用关键字“new”...
  • 当一个对象使用关键字“new”创建时,会堆上分配内存空间,然后返回对象的引用,这对数组来说也是一样的,因为数组也是一个对象;一维数组int[] arr = new int[3];以上代码,arr变量存放了数组对象的引用;...
  • 当一个对象使用关键字“new”创建时,会堆上分配内存空间,然后返回对象的引用,这对数组来说也是一样的,因为数组也是一个对象;一维数组int[] arr = new int[3];以上代码,arr变量存放了数组对象的引用;...
  • 关注Java后端技术栈”回复“面试”获取最新资料Java有两种类型的数组:基本数据类型数组;对象数组;当一个对象使用关键字“new”创建时,会堆上分配内存空间,然后返回对象的引用,这...
  • SystemVerilog是否有一种方法可以创建一个连续分配内存的动态数组?我正在尝试将数据从文件读入动态数组 . 问题似乎是动态数组连续的内存位置,因此文件无法正确读入数组 .当我声明变量读取文件为非动态数组...
  • 当一个对象使用关键字“new”创建时,会堆上分配内存空间,然后返回对象的引用,这对数组来说也是一样的,因为数组也是一个对象;一维数组int[] arr = new int[3];以上代码,arr变量存放了数组对象的引用;...
  • 当使用一个"new"创建一个对象时,分配一段内存空间,并返回一个引用。这一点对于数组也适用,因为java数组也是对象。1.一维数组int arr[] = new int[3];int[] arr仅仅是一个能够存放3个整数的数组的...
  • 在C++ 中,数组在内存分配情况如何呢?我们可以编写如下程序,可以读取到一个二维数组的每一个元素在内存中的地址,为了更清楚的了解,我在这里采用了两种遍历方式: #include "stdafx.h" #include using ...
  • 上次老师跟大家分享了如何优雅导出Excel的知识,今天跟大家分享下Java数组在内存中样子的知识。在Java中,数组存储原始值(int, char,…)或引用(a.k。一个指针)到对象。当使用“new”创建对象时,将在堆中分配内存...
  • c++使用new定义动态数组时,如果数组大小已知,那么会如何分配内存?是程序运行时按照使用的元素数分配还是按照数组大小一次性分配(和普通数组一样的方式)
  • 那么java的int [] arr={1,2,3}是存放什么地方的呢,int []arr = new int[3]又是存放什么地方的呢,下面我们通过编写两个小例子,通过查看生成的字节码文件,来了解jvm会如何来处理这两种情况的。1.int[] arr =...
  • 首先,先简单的来了解下Java内存分配 A:栈 栈是程序运行时单位,决定了程序如何执行,或者说数据如何执行。Java栈内存,以帧的形式存放本地方法的调用状态,包括方法调用的参数、局部变量、中间结果等(方法都...
  • 数组内存控制

    2013-11-01 22:29:08
    1,Java,声明一个数组过程如何分配内存的? 2,java数组初始化一共有哪几种方式? 3,基本类型数组和引用类型数组之间,初始化时的内存分配机制有什么区别?   Java数组是静态的,当数组被初始化...
  • 第一个参数是内存的元素数量(即大小为30 000的数组) . 第二个参数是一个块的大小(即数组中的一个元素) .所以你会这样称呼它:ptr = calloc(30000, sizeof(float));您的情况下使用 calloc 存在一个瓶颈,因为...
  • 如何实现动态分配? 说白了其实就是数组大小由外部输入,然后动态生成数组。 因此添加元素时需要判断数组是否已经满员了,所以类需要一个记录了数组大小的标记,这里记为font 我以下的代码写了一个Array的父类...
  • 【VS开发】【编程开发】【C/C++开发】结构体数组与指针的内存分配情况说明标签:【VS开发】 【编程开发】 主要是疑惑结构体定义的数组内存空间与指针动态分配内存空间,地址上连续性。以及如何访问和...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 796
精华内容 318
关键字:

数组在内存中如何分配