Java基础--数组的认识(通透!!!)

简介: Java基础--数组的认识(通透!!!)

一/简单回顾

基本知识点

  • 数据类型
  • 常量变量
  • 运算符号
  • 分支结构:if switch
  • 循环结构: for while do...while

​ 循环嵌套关系: break continue 标记

二/ 引子

之前我们在学循环的时候,讲到一个例子,不知道大家还记不记得。

int score=90;
根据score成绩来进行区间的判定,不及格/及格/中等/良好/优秀/满分。

之前解决这个问题的时候,我们用到if else语句,后来又可以用switch语句来解决。

那么现在,我们重新来想一下这个问题。

score是一个变量空间(栈内存中的一块空间),可以理解为一个小容器。小容器里面存储的是一个学生的成绩。

②变量有什么特点?

1.变量在创建的时候,类型是固定的

2.空间内的内容只能存放一份


现在再来想一个问题。

如果想将5个同学的成绩都存起来,那我们就需要5个变量。

每次多一个变量,就会多一个名字,不方便。

在现实中,我们就会给他们编一个班级,以班级为的单位。这样就方便多了。

那么,我们同样可以用这种方式来存储数据。

下面要讲到,这种方式就是用数组来存储。

三/ 数组

(1)概念

来看看数组这俩字:

数:数据类型

组:一组元素

数组是一组数据类型相同的数据的结合。

数组也可以看作一份容器

和变量不同的是,变量空间只能存放一份,而数组可以存储一组内容。

将这些数据统一在一起管理起来,更加方便。

(2)性质

之前说过的基本数据类型byte/short/int/long/float/double/char/boolean

引用数据类型数组//接口/枚举/注解等,包括之前咱们接触过的String/Scanner/Math

我们可以看到,数组是一个引用数据类型

(3)写法

1)数组的声明(创建)

①起名字

在学变量的时候,咱们是先定义一下,如int score

那么,同样,在用数组之前,也需要定义一下。

刚才说过,数组和变量类似,可以当作一个容器,存在于栈内存或堆内存当中,在里面开辟了一个空间。

既然是开辟了一个空间,那么就要先给它起一个名字

②添加数据类型

那么数组里面存什么呢?

通过上面的概念,我们知道,数组是一组数据类型相同的数据的结合

虽然数组里面是一组数据,但是要求,数据类型要相同!!!

所以我们在给数组声明的时候,要说明这里面存的是什么。

在名字前面,我们需要添加数据类型

③添加中括号

现在我们得到这样的效果:数据类型 数组名字;

咦,这样不就和变量声明格式一样了吗?怎么表示它是一个数组呢?

为了区分,我们在数据类型之后,添加一个中括号[ ],来表示它是一个数组形式。

如果没有中括号,就表示是一个变量空间,加了中括号,就是数组。

2)举例

通过上面的分析,我们可以得到数组的定义:数据类型[] 数组名字;

那么我们现在举几个例子。

我想创建一个数组,

来存储一些int类型的整数,可以这样写:int[] x;

又比如,存储一组字符类型的数据,可以这样写:char[] y;

存储一些布尔类型的值,可以这样写:boolean[] z;

存储一些字符串形式的数据,可以这样写:String[] m;

:star: ==数组本身是一个引用数据类型,但是,数组内存储的类型,可以是基本类型,也可以是引用类型。==

(里面的每一个元素,什么都可以,只要是相同的类型就行)

3)补充

在书写数组的时候,我们会加上一组中括号表示它是数组。

那这个中括号的位置可以写在哪里呢?

在上面,我们将它写在了数据类型的后面,就是这样:int[] x;

但是,写在数组名字后面也是可以的,就像这样:int x[];

在这里,推荐大家写第一种,写在数据类型后边的,比较标准。


int[] x;这种写法,可以理解为,x是变量名,前面的int[]整体算作一个类型。

在这里,主要想告诉大家,两种写法都可以,都好用,编译器都可以识别,但是规范来说,还是第一种。

在笔试题中,以下这几种写法都是可行的啦。

int[]  x;  -->规范
int    []x;  -->别扭的很(和上面的写法类似,只不过将中括号后移了一点)
int    x[];  -->也可以这样写,但是识别的时候,不好看。

(4)数组的初始化

数组声明之后,我们需要往里面存东西。

数组是一个引用数据类型,既然是引用数据类型,赋值有一个专业的名词,叫做初始化

数组的初始化:创建数组并且给数组赋值。

数组的初始化有两种:静态初始化/动态初始化。

1)静态初始化

举个例子,现在我们要创建一个数组,里面存储整数类型,起个名字叫array。

那么可以这样定义:int[] array;

现在要将它初始化,直接将值赋给它?

有的小伙伴想这样写,都不对哈,看下面的情况(都不对的呦):

<1> 给一个常量是不对的
int[] array=10; -->直接给一个10,肯定不对,数组里面又不是只有一个10,是有好多个这样的类型。
<2> 给一个字符也不对
int[] array=`a`;
<3> 给一个字符串也不对
int[] array="abc"; -->类型不统一

:star:==数组是一个引用数据类型,我们以后,见到的所有引用数据类型,只要想创建,通过的方式是统一的。要new一下。==

这里,就是开辟一个新的数组,给array赋上。

new什么呢?

前面都规定好了,是一个数组类型(int[])。

那么我们肯定要new一个和前面类型一致的!前面的类型是什么,后面就要new什么。

现在我们要的是一个int[]数组类型,那么后面就要new一个数组类型啦。

就像这样:int[] array=new int[];

还记得之前我们说过的Scanner吗?这样写的来着:Scanner x=new Scanner();,这里是圆括号,数组是方括号。

这两个写法很像,xarray都是变量名,Scannerint[]都是一个类型,后面new的过程,都相当于开辟了一个新的空间。

其实这里我们称之为对象更合理一点。


现在我们new过了,那数组里面有什么呢?

我们就需要在后面加上一组大括号,就像这样:int[] array=new int[]{};

大括号表示一组元素,每一个元素都是一个int类型的整数。

现在我们只需要在大括号里面添加数值即可,比如添加10,20,30,40,50这些数据。

那么就可以这样写:int[] array=new int[]{10,20,30,40,50};

这样就写好了,数组的静态初始化的标准写法。

从这个写法上,我们可以看到,数组的长度是5(数组里面的数据的个数);还可以看到每一个元素。

静态初始化,可以看到数组的长度和内容。

好啦,标准的静态初始化写法,我们都已经知道了。

现在再来看一下,它的简洁写法:int[] array={10,20,30,40,50};

可以将new的过程省去不写。

为啥可以这样呢?

数组变量名(array)之前,已经有了定义类型( int[] )。

那么,后面new出来的类型肯定和前面定义的一致。

==在数组定义的时候,前面如果有定义,那么后面的new可以省去不写,变成简洁的写法。==

但是,如果现在只是一个变量名,就不能省去new的过程了!!!

就像这样:

int[] array;
... ...
... ...
array=new int[]{10,20,30,40,50};
1.前面如果有数组类型的定义,就可以省去后面new的过程;

2.但是,如果前面只是一个变量,虽然之前这个变量array已经定义好了类型,但是此时编译的时候,它分不清变量到底什么类型的。这个时候,就必须new一下。

最后,总结一下,静态初始化的两种写法:

int[] array=new int[]{10,20,30,40,50};  -->标准写法
int[] array={10,20,30,40,50};           -->简洁写法

2)动态初始化

:walking: 提示:先跳过这个往后看,最后再来看这个,要不然可能看不懂。跳过看不影响后边的啦,不用担心。

大致和静态初始化一样,但是在创建过程,只给数组的长度,没有元素。

比如,我们有5个元素,可以这样写:int[] array=new int[5];

注意几点:

①创建0长度是可以的。

只不过是创建一个0长度的数组而已。

可以来试一下:

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[0];//创建了一个长度为0的数组
       
    }
}

看一下执行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PNuheiqh-1658502929049)(D:\Typora图片\image-20220722220031220.png)]

我们可以看到,编译(javac)和执行(java)都是可以的。(这里没有做输出,就没有输出什么啦)


②负数也是可以的,但只能通过编译(语法结构正确),不能执行结果。

再来试一试:

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[-1];//创建了一个长度为-1的数组
       
    }
}

看一下错误,是运行时异常

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-caBQ5E4K-1658502929050)(D:\Typora图片\image-20220722220415258.png)]

报错:Negative Array Size Exception,数组的长度不合法(创建数组的时候长度给了负数)。

总结:它认为0是一个正常的整数,可以用。

​ 但是,0长度的数组,创建出来,什么东西都塞不进去,创建出来没有意义。


③动态初始化,只有长度,没有元素,是真的没有元素吗?

我们来试一下:

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[5]; 
        System.out.println(array[0]); 
        //访问数组的第一个元素,如果数组里面没有元素,第一个元素也就不存在
    }
}

看一下运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bPtiwCG2-1658502929050)(D:\Typora图片\image-20220722221427723.png)]

运行结果是0。

大家可以自行尝试其他的位置,可以发现,出来的结果都是0。

我们来全部访问一遍,加强for循环来试一试。(加强for循环后边有讲,不懂的小伙伴转移后方)

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[5]; 
        for(int value:array){
             System.out.println(value);
        }
    }
}

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-omhqh4ue-1658502929051)(D:\Typora图片\image-20220722221748135.png)]

可以看到,最终结果都是0。

由此可见,这里说的,动态初始化,有长度,没有元素,不是真的没有元素,默认值是0。

为啥是0呢?

1.因为是整数呀,整数默认值就是0。

2.如果是浮点数,默认值就是0.0。

3.如果是字符型,默认值就是0对应的char值(97-->a ,65-->A,48-->'0')。

这个大家可以去试一下,打印不出来的,输出的值看不见。

emm,给大家示范一下吧。

代码如下:

public class TestArray{
    public static void main(String[] args){
        char[] array=new char[5]; 
        for(char value:array){
             System.out.println(value);
        }
    }
}

来看一下执行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-erTycbSZ-1658502929052)(D:\Typora图片\image-20220722223338713.png)]

可以看到,打印出来了5个数,但是没有显示。

4.如果是布尔型,默认值就是false。

5.如果是引用数据类型,默认值就是null。

(比如数组,虽然数组是引用数据类型,但是数组里面存储的可以是基本数据类型,也可以是引用数据类型)

如果数组里面每个元素是基本数据类型,那么默认值就是上面的其他情况。

如果数组里面存储的是引用数据类型。比如创建一个数组,存储String类型的数(引用数据类型)。

数组里面每个元素都是引用数据类型,那么默认值就是null

咱们可以试一试:

public class TestArray{
    public static void main(String[] args){
        String[] array=new String[5]; 
        for(String value:array){
             System.out.println(value);
        }
    }
}

看一下运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G7yRRTU1-1658502929053)(D:\Typora图片\image-20220722223027886.png)]


④动态初始化之后,都是默认值,并不是我想要的呀。

我们往里面存了东西,这个数组才有效。

还是拿最开始的整数类型举例。

访问元素,然后存值即可(看不懂如何访问的小伙伴,看后边的讲解哈)。

代码:

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[5]; 
        array[0]=10;
        array[1]=20;
        array[2]=30;
        array[3]=40;
        array[4]=50;
        //可以有array[5]吗?不可以的,会出现Array Index Out Of Bounds Exception的错误(后边有讲呦)
    }
}

最后,总结一下,动态初始化的写法:

int[] array=new int[5];

3)总结

静态和动态都有new的过程。

静态初始化:有长度,有元素。

动态初始化:有长度,没有元素(不是真的没有,是默认值),需要往里面放东西才能用。

==所有引用类型,都得用new关键字来创建。==

除非有特殊情况,比如Math.random();,虽然是引用类型,但从不用new对象。

为啥呢?

因为random()方法是一个静态方法,是一个static修饰的静态方法。

这个静态方法,在整个类(Math类)中就一份,不需要创建对象,通过类名可以直接访问!!!

(5)数组元素的访问并应用

1)访问数组元素

数组的定义和初始化,咱们都已经学会了。

那么,数组作为一个容器,里面存的值得用呀。

那么我们如何访问数组里面的元素呢?

举个小例子:

现在我们定义了如下数组,想访问10这个元素,该怎么办呢?

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[]{10,20,30,40,50};
        
    }
}

以前定义变量的时候,想要拿出来用,只需要把变量名拿过来即可。

但是现在,是一个数组,数组名array代表的不是一个数,而是5个数。

我们这样来理解:

array相当于一个班级,里面有5个人,叫10,20,30,40,50。

现在只有一个班级名array,而没有5个人的人名,现在想要10,咋办?

我们可以这样,array班级中的第一个同学。

通过班级名找到第一个同学,就找到10啦!

那么,同样,我们可以访问第二个,第三个同学。

:star:==可以通过访问元素在数组中的位置,来访问每个元素。==


数组中元素的位置如何定义?

利用索引(index),即数组中每个元素所在的位置。

计算机中,是从0开始数的。

索引号是从0开始数的。

我们要访问元素,就可以这样访问:array[index];

现在我们要访问数组第一个位置,就可以这样写:array[0];

2)取出数组元素

既然拿出来了,就要存着用啊,可以用一个变量将它存起来,这个变量的数据类型必须要和这个拿出来的数据的数据类型一致。

比如这里,就要用int类型的变量来存储拿出来的数据。

这里定义一个变量value来存储这个数。

可以这样写:int value=array[0];

我们可以输出一下这个value,来看看输出的值是不是数组第一个数。

代码如下:

public class TestArray{
    public static void main(String[] args){
        //数组array的初始化
        int[] array=new int[]{10,20,30,40,50};
        //从数组内取得某一个位置的元素,并存入变量value中
        int value=array[0];
        //输出
        System.out.println(value);
    }
}

运行一下(这里用dos窗口运行的,具体怎么操作可以看我之前的文章):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BLwdNyaX-1658502929054)(D:\Typora图片\image-20220722185439678.png)]

可以看到,结果输出就是10,就是数组第一个数。

3)替换数组元素

现在我们想让40变成60。

①先访问40这个元素,它是在数组里面的第4个数,索引号是3。(索引是从0开始计数的呦)这样写array[3]

②将400存入这个位置即可,这样写array[3]=400;。就当这个位置是个变量,将400赋值给这个变量即可。

③输出这个位置的元素,看一看是不是真的换啦。

代码如下:

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[]{10,20,30,40,50};
        //向数组内的某一个位置存入元素
        array[3]=400;
        System.out.println(array[3]);
    }
}

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VD0JSxJ7-1658502929056)(D:\Typora图片\image-20220722191023314.png)]

可以看到,数组第4个元素,变成了400。

数组元素的每一个位置,可以认为是一个小变量,一个小格子。

可以从这个小格子里面取值,也可以往里面放值。

4)数组元素的遍历(轮询)

数组元素的遍历即取出数组所有元素。

刚才我们取的都是一个元素,现在我想取出数组中所有的元素。

<1> 分析

我们访问每个元素,是这样写的:array[index]

这时候,我们要想把元素都拿出来看一看,就需要用到循环

【第一次是array[0],第二次是array[1]……(每次都是做同样的事情,而且索引号有规律)】

用什么循环呢?forwhile都一样。

我们这里用for循环演示。(为啥想到循环,是因为我们想让程序每次都给咱们做同样的事情:取数组的值)

:question: 这里需要循环几次呢?5次(一共5个数嘛)。

5次循环,从几数到几,比较方便呢?

循环的目的只是执行5次,我想从几开始数都可以,只要是5次就好啦。比如,100-104,或者1000-1004,都可以。

循环跟取值从几开始没有关系的,但是5次从几次开始数比较方便?

如果循环乱开始数,里边每次取数组元素,就不太方便。因为数组本身还有索引号,还得重新找个变量来控制它。

如果这五次刚好和索引号对上,那么就可以将循环的变量来当索引号!!!

<2> 正常循环遍历

:red_car: 根据上面的分析,循环的开始值,可以从0开始(索引号index从0开始的)即index=0

用它既当循环的变量,又可以当索引的变化。这样比较方便,省了一个变量啦。

那么,到什么时候结束?index<=4或者index<5

这里的index就有两个作用。第一,控制循环次数变化(5次);第二,控制索引变化(index变化和索引变化对上了)。

综上,循环部分就可以这样写for(int index=0;index<5;index++){}

代码如下:

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[]{10,20,30,40,50};
        for(int index=0;index<5;index++){ //每一次做一样的事情,即取数组的值,一共5次
            int value=array[index]; //将取得的值放入变量value中
            System.out.println(value); //将它们输出看一看
        }
    }
}

编译运行结果:

在这里插入图片描述

<3> 增强for循环

上面的for循环,是一般写法,还有一种增强的写法。不过对JDK版本有要求。

JDK 1.5版本之后,有了很多新的特性,其中有一个就是:增强for循环(ForEach)。

刚才我们写的for循环有3个要素,用两个分号表示,三个要素必须执行,即:

for(;;){
    
}

加强for循环之后呢,小括号之间不再是三要素了,中间也不是分号了。

中间写的是冒号

冒号将括号隔成两个部分,分别是,自己定义的变量(作用是接收数组内每一个元素):遍历的数组array,即:

for(自己定义的变量(作用是接收数组内每一个元素):遍历的数组array){
    
}

那么上面的问题,就可以这样来写啦:

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[]{10,20,30,40,50};
        for(int value:array){ 
            //冒号后面是循环的数组,即array
            //冒号前面是人为定义的变量,用来接收数组内每一个元素
            //(array数组内每一个元素都是int类型,那么用来接收的变量也应该是int类型的)
            System.out.println(value); 
        }
    }
}

然后编译运行,看一下结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jaku2o6e-1658502929058)(D:\Typora图片\image-20220722212419077.png)]

<4> 总结

正常的for循环加强的for循环,都要会!!!

存在即合理,两个for循环都有各自的好处。

①正常的for循环

优点:

​ 有三个必要条件,可以通过index索引找到某一个元素的位置;

​ 而且可以往数组里面存值或取值,因为是直接访问数组的元素位置。

缺点:

​ 写法相对比较麻烦而已。

②增强for循环

优点:

​ 有两个条件,一个是用来取值的变量,一个是用来遍历的数组。

​ 没有index索引,写法相对比较容易。

缺点:

​ 没有index索引,找不到元素到底是哪一个。

​ 而且只能取值不能存值。(如果取值,直接拿出来用就好了;但如果存值,可不行)

​ 有的小伙伴可能会这样写,让value直接等于100。

​ 这样写是不对的,100存到value里面了,而不是数组里面!

for(int value:array){
    value=100; //这样写是不对的,100是存到value里面的,而不是数组里面!
    System.out.println(value);
}
做正常遍历输出的时候(只想看看结果), 加强for比较容易。

想要操作数组中每个元素,甚至是某一个元素,索引号很重要,正常的for循环就很好。

(6)索引的范围问题

我们之前提到了索引,这个索引,是有范围限制的。

比如上面的数组,我们可以访问第6个元素吗?(索引是5)

来试一试。

代码如下:

public class TestArray{
    public static void main(String[] args){
        int[] array=new int[]{10,20,30,40,50}; //目前这个数组有5个元素,索引为0~4
        int value=array[5];
        System.out.println(value);
    }
}

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xzMfKqc8-1658502929065)(D:\Typora图片\image-20220722191641132.png)]

明显可以看到,是可以编译的,但不能运行!这里是运行时异常。


我们说一个错误,得说明是编译不行,还是运行有问题。

想要知道最终结果,是有两步操作的。

第一步翻译(javac),翻译了不一定要执行呀。翻译是,写完代码,遵循了正确的语法结构。翻译过去了,就是遵循了合适的语法结构。但是遵循了语法结构,就一定可以用吗?不见得啊。那就要看第二步运行(java)了。

上面的错误,就是明显的翻译正确,但不能用。

当然不能输出啦。

翻译的时候,5是一个有效数字,当然可以编译。

但是执行的时候,在数组的第5个位置上没有这个元素,所以不能输出。

这里出现的错误,就是运行时异常(javac可以过去,一旦java运行就不行了)。

还有一种是编译时异常(javac就过不去),即语法错误。

在未来开发过程中,找异常也是一个很重要的环节,不能小视。光写不会调,那是百搭。

在这里,说一下几个异常,大家见一个记一个就好(记英文)。

不仅要记异常的英文,还要知道异常点在哪里(即因为什么引起的异常),以后遇到这种异常,要学会自己调试过来。

<1>之前说过一个输入,Scanner input.nextInt();

这个输入,只能输入一个数字。

如果输入的不是数字,就会出现这样的异常Input MisMatch Exception输入类型不匹配

<2>这次的异常叫Array Index Out Of Bounds Exception数组索引超出边界异常(数组索引越界)。

这个异常如何产生的?就是数组索引越界了。数组的index索引是:开始(0)~结束(数组长度-1)。

本次案例中,索引是0~4,出现在这个范围之外的都是越界。

<3>上面讲动态初始化的时候,说过一个不常见的错误,在这里一起说了吧。

Negative Array Size Exception,数组的长度不合法(创建数组的时候长度给了负数)。

(7)总结

数组元素的访问:

通过元素在数组中的位置来访问。可以存值或取值。

位置--->index索引

索引是有取值范围的,范围是从【(0)开始~(数组长度-1)结束】,是闭区间,两边都能取到。

如果数组的索引超出了上述范围,会出现一个运行时异常Array Index Out Of Bounds Exception

相关文章
C4.
|
1月前
|
存储 Java 数据处理
Java的数组
Java的数组
C4.
11 0
|
4天前
|
存储 Java 程序员
Java 数组
4月更文挑战第16天
|
26天前
|
Java
java 8 数组转字符串并以逗号分隔
java 8 数组转字符串并以逗号分隔
11 0
|
1月前
|
Java
【Java】数组中的拷贝方法与初步理解深浅拷贝
【Java】数组中的拷贝方法与初步理解深浅拷贝
12 0
|
1月前
|
存储 Java C语言
【Java】以数组为例简单理解引用类型变量
【Java】以数组为例简单理解引用类型变量
14 1
|
1月前
|
存储 Java 索引
Java数组
Java数组
7 0
|
1月前
|
Java
java中判断数组中元素出现的次数
java中判断数组中元素出现的次数
10 0
|
1月前
|
Java
java向数组中插入元素
java向数组中插入元素
9 0
|
1月前
|
存储 Java 索引
JAVA一维数组
JAVA一维数组
19 3
|
1月前
|
Java 索引
JAVA数组的常用方法
JAVA数组的常用方法
17 1