零基础Java第八期:一维数组(1)

手握风云- 2024-10-23 10:35:04 阅读 73

目录

一、 一维数组的基本概念 

1.1. 什么是数组

1.2. 数组的创建及初始化

1.3. 数组的使用

二、数组是引用类型

2.1. 初始JVM的内存分布

2.2. 基本类型变量与引用类型变量

 2.3. 引用变量的理解

2.4. null 

 三、数组的应用场景

 3.1. 作为函数的参数

3.2. 作为函数的返回值


一、 一维数组的基本概念 

1.1. 什么是数组

       当我们需要存储多个类型相同的变量时,如果一个一个去创建会很麻烦 ,此时我们就可以使用数组去简化这类问题。数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间,地址是连续存放的。每个空间有自己的编号,第一个位置的编号为0,即数组的下标。

1.2. 数组的创建及初始化

 (一)数组的创建规则:

数据类型 [] = new 数据类型[N],其中N表示数组的长度。

<code> int[] array1=new int[10];//表示一个可容纳10个int型的数组

double[] array2=new double[20];//表示一个可容纳20个double型的数组

String[] array3=new String[30];//表示一个可容纳30个String性的数组

 (二)数组的初始化 

数组的初始化主要分为动态初始化以及静态初始化。 

(1)动态初始化:在创建数组时,直接指定数组中元素的个数

int[] array=new int[10]

(2) 静态初始化:在创建数组时不直接指定数据元素个数,而直接将具体的数据内容进行指定

int[] array4 = new int[]{0,1,2,3,4,5,6,7,8,9};

double[] array5 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};

String[] array6 = new String[]{"hell", "Java", "!!!"};

       注意:1.静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度   2.静态初始化时, {}中数据类型必须与[]前数据类型一致   3.静态初始化可以简写,省去后面的new T[]。

       如果没有对数组进行初始化,数组中元素有其默认值。如果数组中存储元素类型为基类类型,默认值为基类类型对应的默认值。 

类型 默认值
byte 0
short 0
int 0
long 0
float 0.0f
double 0.0
char /u000
boolean false
String null

        在这里我们只演示boolean和String类型的默认值,代码如下,对此代码进行调试,运行最后一行时,我们就可以看到boolean的默认值为false

<code> public static void main(String[] args) {

boolean[] array=new boolean[3];//默认值为false

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

String[] str=new String[3];

}

 

1.3. 数组的使用

(1)数组元素的访问 

      数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中任意位置的元素 ,即我们可以通过下标来进行打印、修改,并且不能越界访问,否则会出现如下报错。

<code> int[] arrays=new int[]{1,2,3,4};

arrays[2]=10;

System.out.println(arrays[1]);//打印元素

System.out.println(arrays[2]);//修改元素

System.out.println(arrays[4]);//越界访问

(2)遍历数组:将所有元素都访问一遍。

       如果我们一个一个打印,或者对里面的元素进行修改,会非常麻烦。此时我们可以使用for循环来解决。

<code> int[] arrays = new int[]{1,2,3,4,5,6};

for(int i=0;i<=5;i++){

System.out.println(arrays[i]);

}

     我们来对此代码进行调试,当运行到“System.out.println(arrays[i]);”时,就会产生如下图所示。

       虽然for循环可以帮助我们解决上面提到的问题,但是我们无法获取数组的长度。那我们就可以通过下面的代码来进行实现。

<code> int[] arrays = new int[]{1,2,3,4};

for(int i=0;i< arrays.length;i++){

System.out.print(arrays[i]);

}

System.out.println();

for (int x:arrays) {

System.out.println(x);

}

      第一种是for循环,原理不必多说;第二种是for-each,原理是遍历数组,将数组中的元素赋值给x,但这种方法无法获取数组元素的下标,也无法对下标进行运算。

     当然还有第三种打印方式,是由Java官方提供操作数组的工具,代码如下:

import java.lang.reflect.Array;

import java.util.Arrays;

public class Main {

public static void main(String[] args) {

int[] arrays=new int[]{1,2,3,4,5};

String ret=Arrays.toString(arrays);

System.out.println(ret);

}

}

         Array需要导入一个Arrays的包,我们可以查看一下toString的源码,是String类型的,所以使用String ret来接收一下,直接打印ret就可以了。 下图为打印结果。

二、数组是引用类型

2.1. 初始JVM的内存分布

       我们经常说数组是引用变量,数组里的元素是如何储存在数组里的呢?要想搞清楚这两个问题,那我们首先需要了解JVM的内存分布。

       我们可以把JVM理解为一个大房子,房子分为客厅、厨房、卧室、厕所。同样,JVM也可以划分出多个内存空间,如下图所示。设想一下,如果我们的房子非常乱,找起东西来就会很麻烦。如果对内存中存储的数据不加区分的随意存储,那对内存管理起来将会非常麻烦。

 

2.2. 基本类型变量与引用类型变量

       基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;而引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址。 好,我们来看下面一组代码:

<code>public static void main(String[] args){

int a = 1;

int[] arrays = {1,2,3,4,5};

      arrays就是一个局部类型的引用变量,数组里的元素会在堆上有一个地址,arrays这个变量就会在栈上存这个地址;a也是main方法里的局部变量,它只会在栈上开辟内存空间,就不会在堆上。所以引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始地址。通过该 地址,引用变量便可以去操作对象。

 

 2.3. 引用变量的理解

看下面一组代码:

<code> public static void main(String[] args) {

int[] array1 = new int[3];

array1[0] = 10;

array1[1] = 20;

array1[2] = 30;

int[] array2 = new int[]{1,2,3,4,5};

array2[0] = 100;

array2[1] = 200;

array1 = array2;//重点,必须理解

array1[2] = 300;

array1[3] = 400;

array2[4] = 500;

for (int i = 0; i < array2.length; i++) {

System.out.println(array2[i]);

}

}

       array1=array2,相当于我们把array2的地址赋给了array1,则array1就不能存原来的地址,这样就会造成两块引用同时指向一个空间,相当于通过array1去修改并访问array2,所以说打印出来的值则为100、200、300、400、500。那array1之前所指向的内存空间呢?答案是被回收掉了。

2.4. null 

       null 的作用类似于 C 语言中的 NULL (空指针), 都是表示一个无效的内存位置.。因此不能对这个内存进行任何读写操作。 一旦尝试读写, 就会抛出 NullPointerException,说明某个引用为空,访问了一个空的引用。

<code>public class Main {

public static void main(String[] args) {

int[] array1 = {1,2,3};

System.out.println(array1);//打印结果是16进制的地址

int[] array2 = null;//array2属于引用类型,默认值不能为0

// array引用不指向任何对象

System.out.println(array2.length);//null不指向任何对象,运行就会显示空指针异常

}

}

     博主还留下了两个问题给你去思考:1、引用可以指向引用吗? 2、一个引用可以指向多个对象吗?好,第一个问题:array1=array2,上面我们提到了,array1指向的是array2所指向的对象。第二个问题:一个引用只能指向一个对象,比如 int a=10,不能说a在栈上存储了10个数据吗。

 三、数组的应用场景

 3.1. 作为函数的参数

public class Main {

public static void print(int[] array){

for (int i = 0; i < array.length; i++) {

System.out.print(array[i]);

}

System.out.println();

}

public static void main(String[] args) {

int[] array={1,2,3};

print(array);

}

}

        虽然两个引用都指向了同一个对象,但两个引用的作用域不一样,上面的array是形参,下面的array是实参 ,打印出来的结果就是1 2 3。在这种情况下,我们修改形参的值, 不影响实参的值。那如果我们来看下面一组代码,参数传数组类型呢?

       两个方法都是传递引用类型,第一个方法改变了形参的地址,形参的指向被改变了;而第二个方法中,形参修改了指向对象的内容。 

<code>public class Main {

public static void func1(int[] array){

array =new int[]{10,20,30,40,50};

}

public static void func2(int[] array){

array[0]=10;

}

public static void main(String[] args) {

int[] array={1,2,3};

func1(array);

print(array);

main1(args);//在main方法中,我们调用main1,就可以同时运行main和main1

}

public static void main1(String[] args) {

int[] array={1,2,3};

func2(array);

print(array);

}

 

3.2. 作为函数的返回值

我们都知道调用方法时,只能返回一个值,那我们可以使用数组来进行多个返回值的接收,代码如下:利用ret来接收,并返回给array。

<code>import java.util.Arrays;

public class Main {

public static int[] test(){

int[] ret=new int[2];

ret[0]=10;

ret[1]=20;

return ret;

}

public static void main(String[] args) {

int[] array=test();

System.out.println(Arrays.toString(array));

}

}

 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。