0


数组的定义与使用(一)

就是这篇博客,CSDN富文本编辑器里面ctrl+z把我5000字全给弄没了,我真的哭晕在键盘上,最后还是含着眼泪写完了这篇博客,尽量做到比之前更加详细,只要大家的支持和关注,就是误删了八百万字我也重写/(ㄒoㄒ)/~~

好,那我们进入正题

【本节目标】

  1. 🤯理解数组的基本概念
  2. 🤯掌握数组的基本用法
  3. 🤯数组与方法互操作
  4. 🤯熟练掌握数组相关的常见问题和代码

数组的基本概念

为什么要使用数组?

回答:简化代码,集合管理。

举个简单里例子,我们现在要存入5个学生的JavaSE考试成绩,并对其进行输出

如果这样写的话,太麻烦了:

public class TestStudent{
    public static void main(String[] args){
        int score1 = 70;
        int score2 = 70;
        int score3 = 70;
        int score4 = 70;
        int score5 = 70;
        
        System.out.println(score1);
        System.out.println(score2);
        System.out.println(score3);
        System.out.println(score4);
        System.out.println(score5);
    }
}

这段代码没有问题,但是过多的话就不好管理,

它们都有一个共同点,数据类型都是相同的,那么我们就可以利用数组来集约化管理

什么是数组

数组:可以看成时相同类型元素的一个集合。在内存中时一段连续的空间。

  1. 🎏数组中存放的元素类型相同
  2. 🎏数组中空间连接在一起
  3. 🎏每个空间有着自己的编号,其首位的位置的编号为0,即数组的下标。

那么在程序中我们应该如何创建数组呢?

数组的创建以及初始化

数组的创建

T[] 数组名 = new T[N];

T:表示数组中存放元素的类型

T[]:表示数组的类型

N:表示数组的长度

int[] array1 = new int[10];//创建一个可以容纳10个int类型元素的数组
double[] array2 = new double[5];//创建一个可以容纳5个double类型元素的数组
String[] array3 = new String[3];//创建一个可以容纳三个字符串元素的数组

  public static void main1(String[] args) {
        int[] array = {1,2,3,4,5,6,7,8,9,10};

        int ret = array[2];
        System.out.println(ret);
//      下标默认从0开始

        int[] array2 = new int[]{1,2,3,4,5,6,7,8,9,10};
//      两种是一样的,一般用第一种
        int[] array3 = new int[10];
//      不确定里面放什么的话,就用第三种
    }
}

数组的初始化

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

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

int[] array = new int[10];

2、🧇静态初始化:在创建数组时不直接指定数组元素个数,而直接讲具体的数据内容惊醒指定

语法格式:T[] 数组名称 = {data1,data2,data3......}

 public static void main3(String[] args) {
        int[] array ;
//      我们称这样为动态初始化
        array = new int[]{1,2,3,4,5};
        array = new int[]{9,8,7,6,5};
//      这样重新定义是可以的

        int[] array2 = {1,2,3,4,5};
//      我们称这么做为静态初始化
//
//      array2 = {9,8,7,6,5}这样写会报错,因为定义数组的时候整体赋值,只有一次机会
    }

    public static void main2(String[] args) {
        double[] array = new double[10];
        String[] strings = new String[10];
//      此时我们并没有初始化,但静态初始化虽然没有指定数组的长度,编译器会自动帮你确定

    }

注意事项:

👉🍔静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中的元素个数来确定 数组的长 度

👉🍳静态初始化时,{}中数据类型必须与[]前数据类型一致。

👉🌭静态初始化可以简写,省去后面的new T[]

👉🍿数组也可以按照如下C语言个数创建,但是最好不要这么做咯👇

/*

该种定义方式不太友好,容易造成数据的类型就是int的误解

[]如果在类型之后,就表示数组类型,因此int[]结合在一起写,意思更加明了

**/*

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

👉🍟如果不确定数组当中内容时,使用动态初始化,否则建议使用静态初始化

👉🍱静态和动态初始化也可以分为两步,但是省略格式不可以,上面代码中有提到

例如这样就会编译失败→int[] arr3; arr3 = {1,2,3}

👉🍘如果没有对数组进行初始化,数组中元素有其默认值

1、如果数组中存储元素类型为基本类型,默认值时基类类型对应的默认值,如:
类型默认值byte0short0int0long0float0.0fdouble0.0char/u0000booleanfalse
2、如果数组中存储元素类型为引用类型,默认值为null.

数组的使用

数组中元素访问

数组在内存中是一段连续的空间,空间的编号都是从0开始的,依次递增,该编号成为数组的下标,数组可以通过下标访问其任意位置的元素。比如:

   public static void main3_3(String[] args) {
        int[] array = new int[]{10,20,30,40,50};
        System.out.println(array[0]);
        System.out.println(array[1]);
        System.out.println(array[2]);
        System.out.println(array[3]);
        System.out.println(array[4]);
        
//        也可以通过[]对数组中的元素进行修改
        array[0] = 100;
        System.out.println(array[0]);
    }

【注意事项】

  1. 🍡数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中任意位置的元素
  2. 🍭下标从0开始,介于[0,N)之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常。

这里的红字异常就是提醒我们使用数组一定要下标谨防越界

遍历数组

所谓的“遍历”是指讲数组中的所有元素都访问一遍,访问是指对数组中的元素进行某种操作,比如:Print.

上述代码可以起到对数组中元素遍历的一个目的,但任然有一些问题:

  1. 🛹如果数组中增加了一个元素,就需要增加一条打印语句
  2. 🚃如果输入里面有100个元素,就需要去写100个打印语句
  3. 🌎如果现在要把打印修改为给数组中每个元素加一个数,会非常麻烦。

那么细心的小伙伴们就会想到了,我们可以运用循环来进行打印。

下面介绍一些循环遍历的方法👇

1、基本for循环

PS:在数组中,我们可以通过 ***数组对象.length ***来获取数组的长度

2、for-each进阶法——for增强版💪

for-each是for循环的另外一种使用方法,能够更方便得完成对数组得遍历。可以避免循环条件和更新语句写错。 (循环每次都会把array数组中的元素逐个赋给x)

3、超级简便toString法

我们会常常这样打印

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

嗨嗨!每天一个小细节,学到了!

数组是引用类型

初始JVM的内存分布

内存是一段连续的储存空间,主要用来存储程序运行时数据的。比如:

  1. 💰程序运行时代码需要加载到内存
  2. 📸程序运行时产生的中间数据要存放在内存
  3. 🎥程序中的常量也要保存
  4. 🎸有些数据可能需要长时间的存储,而有些数据当方法运行结束后就要被销毁

如果对内存中存储的数据不加区分的随意存储,那对内存管理起来会非常麻烦

就像一个房间从这样

经过管理之后变成这样

因此为了管理内存,JVM也对所使用的内存按照功能的不同进行了划分

  • 🚗程序计数器(PC Register):只是一个很小的空间,用来保存下一条执行的指令的地址
  • 🚓虚拟机栈(JVM Stack):与方法调用相关的一些信息,每个方法在执行的时候,都会先创建一个栈帧(啊啊啊啊啊啊啊又是让我破大防的栈帧!),栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。当方法运行结束之后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
  • 🚕本地方法栈(Native Method Stack):本地方法栈与虚拟机栈的作用类似,只不过保存的内容时Native方法的局部变量。在有些版本的JVM实现中(例如HotSpot),本地方法栈和虚拟机栈是一起的。
  • 🛺(Heap):JVM所管理的最大内存区域。使用new创建的对象都是在堆上保存的(例如new int[] {1,2,3}),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在石油,就不会被销毁。
  • 🚙方法区(Method Area):用于存储已经被虚拟机加载的类信息、常量、静态变量、即使编译器编译过后的代码等数据。方法编译出来的字节码就是保存在这个区域内的

我们在C语言中一般都需要用malloc();来开辟动态内存,然后再去用free()释放

但是在Java中,堆上开辟的内存不需要我们进行释放,JVM本身具有的垃圾回收机制可以帮我们进行这些操作

这一块的内容就不多做解释了,等以后我了解得更透彻更详细会再进行细说

基本类型变量与引用类型变量的区别

基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的时其所对应的值;

而引用数据类型创建的变量,我们一般称之为对象的引用,其空间中存储的是对象所在空间的地址值。

上面的代码中,a,b,arr,array1都是函数内部的变量,因此其空间都在main方法对应的栈帧中分配。

a、b是内置类型的变量,因此其空间中保存的就是给该变量初始化的值。

array是数组类型的引用变量,其内部保存的内容可以简单理解成是数组在堆空间中的首地址

我们从上面的图中可以见到,引用变量并不直接储存对象本身,可以简单理解为储存的是对象在堆中空间的起始地址。通过该地址,引用变量便可以再去操作对象。这么做有点类似于C语言中的指针,但是Java中引用要比指针的操作简便更多。

引用变量(进阶)

话不多说,咱们直接上代码👇

//    对象  引用
    public static void main7(String[] args) {
        int[] array1 = {1,2,3,4};
        int[] array2 = array1;
        System.out.println("array1:" + Arrays.toString(array1));
        System.out.println("array2:" + Arrays.toString(array2));

        System.out.println("======================");
        array2[0] = 99;
//        这样用array2改变首元素的值时,我们测试可以发现array1[0]也变了
        System.out.println("array1:" + Arrays.toString(array1));
        System.out.println("array2:" + Arrays.toString(array2));

        int[] array3={1,2,3,4};
        int[] array4={5,6,7,8};
        array3=array4;
//        这个时候{1,2,3,4}这块内存就被JVM的垃圾回收机制回收了
        System.out.println(Arrays.toString(array3));
        System.out.println(Arrays.toString(array4));
    }

    public static void main6(String[] args) {
//        该方法用于了解引用变量
        int[] array = {1,2,3};
        double[] array2 ={1.0,2.0,3.0};
        System.out.println(array);
        System.out.println(array2);
        int[] array3 = null;//代表array这个引用变量不指向任何对象
//        不能用int array3 = 0;来初始化引用变量
//        而且这个时候 System.out.println(array3);的话
//        会显示空指针异常
//  System.out.println(array3[0]);也会显示空指针异常
//        既然引用变量为null了,那么就不能用array.length以及其他类似的用法了,会报错

    }

上述图片中的初始化方法中省略了new,但编译器还是当作new了一块内存处理。

认识null

null在Java中表示“空引用”,也就是一个不指向对象的引用

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

注意:Java中并没有约定null和0号地址的内存有任何关联

一些引用变量的问题:

数组的应用

保存数据

public static void main (String[] args) {
    int[] array = {1,2,3};

    for(int i =0;i < array.length;++i){
        System.out.println(array[i] + " ");
    }
}

作为函数的参数

1、参数传递基本数据类型

 public static void func2(int[] array){//在栈上新分配一块array引用变量的空间,也指向main_func2中的{1,2,3,4}
        array = new int[]{11,12,13,14};//这里在堆上新new了一块数组对象{11,12,13,14},array指向该对象
    }
//这里有个重要的概念,在Java中,都是按值传递,地址也是值
    public static void main_func2(String[] args) {
        int[] array1={1,2,3,4};
        func2(array1);//这里把array1的地址值传过去了,
        System.out.println(Arrays.toString(array1));
    }
//    输出结果为1 2 3 4

这里在方法中修改形参的值,其实并不影响实参的num值

2、参数传递数组类型(引用数据类型)

我们发现在func方法内部修改数组的内容,方法外部的数组内容也发生改变,

因为数组式引用类型,按照引用类型来进行传递,是可以修改其中存放的内容的。

总结:所谓的“引用”本质上只是存了一个地址。Java将数组设定成引用类型,这样的话后续进行数组参数传参,其实只是将数组的地址传入到方法形参中,这样可以避免堆整个数组的拷贝,对内存的无谓损耗。

测试实验的代码如下👇

//实验一
public static void func1(int a) {
        a=20;
    }
    public static void main9(String[] args) {
        int x =10;
        func1(x);
        System.out.println(x);
    }
//实验二
public static void func2(int[] array){//在栈上新分配一块array引用变量的空间,也指向main_func2中的{1,2,3,4}
        array = new int[]{11,12,13,14};//这里在堆上新new了一块数组对象{11,12,13,14},array指向该对象
    }
//这里有个重要的概念,在Java中,都是按值传递,地址也是值
    public static void main_func2(String[] args) {
        int[] array1={1,2,3,4};
        func2(array1);//这里把array1的地址值传过去了,
        System.out.println(Arrays.toString(array1));
    }
//    输出结果为1 2 3 4
//实验三
public static void func3(int[] array){
        array[0]=199;//array指向的下标为0的元素值改为199
    }
    public static void main_func3(String[] args) {
        int[] arr = {100,99,88,77};
        func3(arr);
        System.out.println(Arrays.toString(arr));
    }
//    输出结果为199,99,88,77

下面是本篇博客用到的源代码,需要回顾一下的可以参考参考。

import java.util.Arrays;

/**
 * Created with IntelliJ IDEA.
 * Description: Hello,I would appreciate your comments~
 * User:
 * Date: -03-20
 * Destination:
 * 1、如何定义数组?
 * 2、如何初始化数组?
 * 2、如何打印输出数组?
 */
public class arrDemo {

    /**第四种拷贝方法
     * array.clone();
     * @param args
     */
    public static void main_copy4(String[] args) {
        int[] array = {1,2,3,4};
        int[] copy = array.clone();
        System.out.println(Arrays.toString(copy));
        System.out.println(array);
        System.out.println(copy);
//        输出的地址不一样,说明新开辟了一个引用变量之后,新new并且指向了一个对象
    }

    /**第三种拷贝方式
     * 利用arraycopy
     * @param args
     */
    public static void main_copy3(String[] args) {

        int[] array = {1,2,3,4};
        int[] copy = new int[array.length];

        System.arraycopy(array,0,copy,array.length,array.length);

        System.out.println(Arrays.toString(copy));
    }

    /**第一种拷贝方法
     * 利用Array类的从copyOf方法来进行拷贝(你要拷贝的数组,返回的数组长度)
     * @param args
     */
    public static void main_copy2(String[] args) {
        int[] array = {1,2,3,4};
        int[] copy = Arrays.copyOf(array,array.length);
        int[] copy2 = Arrays.copyOf(array,2*array.length);
        System.out.println(Arrays.toString(copy));
        System.out.println(Arrays.toString(copy2));
//        其实是扩容
    }

    /**第一种拷贝方法
     * 使用for进行拷贝
     */
    public static void main_copy(){
        int[] array = {1,2,3,4};

        int[] copy = new int[array.length];

        for (int i=0;i<array.length;i++){
            copy[i] = array[i];
        }
        System.out.println(copy);
    }

    /**
     * 题目1:这里写一个函数将一维数组以字符串的形式进行输出[1,2,3,4]
     * @param array
     * @return
     */
    public static String myToString(int[] array){
        String string="[";
        for(int i =0;i<array.length;i++){
            string+=array[i]+"";
            if(i!=array.length-1){
                string +=",";
            }
        }
        string+="]";
        return string;
    }
    public static void main_myToString(String[] args) {
        int[] array = {1,2,3,4};
        String ret = myToString(array);
        System.out.println(ret);
    }

    public static void main(String[] args) {
        int[] arr = {1,2,3};
        func(arr);
        System.out.println("arr[0] = " + arr[0]);
    }
    public static void func(int[] a) {
        a[0] = 10;
        System.out.println("a[0] = " + a[0]);
    }

    public static void func2(int[] array){//在栈上新分配一块array引用变量的空间,也指向main_func2中的{1,2,3,4}
        array = new int[]{11,12,13,14};//这里在堆上新new了一块数组对象{11,12,13,14},array指向该对象
    }
//这里有个重要的概念,在Java中,都是按值传递,地址也是值
    public static void main_func2(String[] args) {
        int[] array1={1,2,3,4};
        func2(array1);//这里把array1的地址值传过去了,
        System.out.println(Arrays.toString(array1));
    }
//    输出结果为1 2 3 4

    public static void func3(int[] array){
        array[0]=199;//array指向的下标为0的元素值改为199
    }
    public static void main_func3(String[] args) {
        int[] arr = {100,99,88,77};
        func3(arr);
        System.out.println(Arrays.toString(arr));
    }
//    输出结果为199,99,88,77

    public static void func1(int a) {
        a=20;
    }
    public static void main9(String[] args) {
        int x =10;
        func1(x);
        System.out.println(x);
    }

    public static void main8(String[] args) {
        int a = 10;
        int b = 20;
        int[] arr = new int[]{1,2,3};

        int [] array1 = {1,2,3,4};
        array1 = new int[]{11,12,13,14};
        array1 = new int[]{6,7,8,9};
    }

//    对象  引用
    public static void main7(String[] args) {
        int[] array1 = {1,2,3,4};
        int[] array2 = array1;
        System.out.println("array1:" + Arrays.toString(array1));
        System.out.println("array2:" + Arrays.toString(array2));

        System.out.println("======================");
        array2[0] = 99;
//        这样用array2改变首元素的值时,我们测试可以发现array1[0]也变了
        System.out.println("array1:" + Arrays.toString(array1));
        System.out.println("array2:" + Arrays.toString(array2));

        int[] array3={1,2,3,4};
        int[] array4={5,6,7,8};
        array3=array4;
//        这个时候{1,2,3,4}这块内存就被JVM的垃圾回收机制回收了
        System.out.println(Arrays.toString(array3));
        System.out.println(Arrays.toString(array4));
    }

    public static void main6(String[] args) {
//        该方法用于了解引用变量
        int[] array = {1,2,3};
        double[] array2 ={1.0,2.0,3.0};
        System.out.println(array);
        System.out.println(array2);
        int[] array3 = null;//代表array这个引用变量不指向任何对象
//        不能用int array3 = 0;来初始化引用变量
//        而且这个时候 System.out.println(array3);的话
//        会显示空指针异常
//  System.out.println(array3[0]);也会显示空指针异常
//        既然引用变量为null了,那么就不能用array.length以及其他类似的用法了,会报错

    }

    public static void main5(String[] args) {
        int a = 10;//局部变量=》存放到  栈【虚拟机栈】中
    }

    public static void main4(String[] args) {
//      该main方法解释如何打印输出数组内容
        int[] array = {1,2,3};
        for(int i=0;i<array.length;i++){
            System.out.println(array[i]+" ");
        }
//      第一种,普通for循环
        for( int x : array ){
            System.out.println(x+" ");
        }
//      第二种for-each   for循环的增强版

//      第三种,借助Java本身带有的一些方法来实现数组的打印Array
        String ret = Arrays.toString(array);
//        把参数的数组转化成字符串进行输出
        System.out.println(ret);
//        输出带有中括号是因为方法内部自动帮你包装了一下
        System.out.println(Arrays.toString(array));
    }

    public static void main4_1(String[] args) {
        int[] array = new int[]{10,20,30,40,50};
        System.out.println(array[0]);
        System.out.println(array[1]);
        System.out.println(array[2]);
        System.out.println(array[3]);
        System.out.println(array[4]);
    }

    public static void main3_4(String[] args) {
        int[] array = {1,2,3};
        System.out.println(array[3]);
    }

    public static void main3_3(String[] args) {
        int[] array = new int[]{10,20,30,40,50};
        System.out.println(array[0]);
        System.out.println(array[1]);
        System.out.println(array[2]);
        System.out.println(array[3]);
        System.out.println(array[4]);

//        也可以通过[]对数组中的元素进行修改
        array[0] = 100;
        System.out.println(array[0]);
    }

    public static void main3(String[] args) {
        int[] array ;
//      我们称这样为动态初始化
        array = new int[]{1,2,3,4,5};
        array = new int[]{9,8,7,6,5};
//      这样重新定义是可以的

        int[] array2 = {1,2,3,4,5};
//      我们称这么做为静态初始化
//
//      array2 = {9,8,7,6,5}这样写会报错,因为定义数组的时候整体赋值,只有一次机会
    }

    public static void main2(String[] args) {
        double[] array = new double[10];
        String[] strings = new String[10];
//      此时我们并没有初始化,但静态初始化虽然没有指定数组的长度,编译器会自动帮你确定

    }

    public static void main1(String[] args) {
        int[] array = {1,2,3,4,5,6,7,8,9,10};

        int ret = array[2];
        System.out.println(ret);
//      下标默认从0开始

        int[] array2 = new int[]{1,2,3,4,5,6,7,8,9,10};
//      两种是一样的,一般用第一种
        int[] array3 = new int[10];
//      不确定里面放什么的话,就用第三种
    }
}

就到这里吧,剩下数组的应用也是一块比较重要的内容,等我学透了再帮大家整理~

还有!千万不要在CSDN里面频繁使用ctrl z!这次真的吃大亏了/(ㄒoㄒ)/😣

感谢阅读!

标签: java 数据结构

本文转载自: https://blog.csdn.net/qq_63511424/article/details/123623922
版权归原作者 Gremmie102 所有, 如有侵权,请联系我们删除。

“数组的定义与使用(一)”的评论:

还没有评论