JavaSE - 数组的定义、使用、内存分布、应用

目录

1. 数组的定义

2. 数组的使用

2.1 访问数组

2.2 遍历数组

2.3 练习:改变原有数组元素的值

3. 数组是引用类型

3.1 内存分布 

3.1.1 初始JVM的内存分布

3.1.2 与C语言的内存分布简单做个对比

3.1.3 在Java和C中数组存储位置有什么区别吗?

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

3.3 通过一些题进一步理解引用

题目一:

题目二:

​题目三:

4. 数组的应用(引用/数组名的应用)

4.1 保存数据

4.2 作为函数的参数

4.2.1  

4.2.2 交换两个值:

4.3 作为函数的返回值

5. 数组的练习:  Arrays -> 操作 数组相关的 工具类

5.1 数组转字符串:Arrays.toString(数组名) 

5.2 数组拷贝: Arrays.copyOf()  、  Arrays.copyOfRange()                                         需要拷贝的数组.clone()    、 arraycopy 

5.2.1 Arrays.copyOf(original,new length)

5.2.2 Arrays.copyOfRange(original,from,to) 

5.2.3 需要拷贝的数组 . clone()

5.2.4 arraycopy(要拷贝哪个数组, 从哪个位置开始拷, 往哪个数组里拷, 拷贝到数组的哪个位置, 拷多长)

5.2.5 自己实现一个数组拷贝

5.3 查找数组中指定元素:顺序查找、二分查找

5.3.1按顺序查找

5.3.2 Arrays.binarySearch(要查找的数组,要查找的元素)

5.3.3 自己实现一个二分查找

5.4 数组排序

5.4.1 Arrays.sort

5.4.2 冒泡排序

5.5 比较两个数组是否相等:Arrays.equals(数组名1,数组名2)

5.6 给数组初始化:Arrays.fill()

5.6.1 全部初始化为同一个值:Arrays.fill(需要初始化的数组,初始化成的值)

5.6.2 部分初始化为同一个值:Arrays.fill(要初始化的数组,from,to,初始化成的值)

5.7 数组逆序

6. 二维数组

6.1 二维数组的定义

6.2 数组的使用

6.2.1 二维数组是特殊的一维数组

6.2.2 一维数组和二维数组在内存中存储的对比图

6.2.3 遍历二维数组

6.3 不规则的二维数组 


1. 数组的定义

数组是一块连续的存储空间,存储的是一组相同类型的元素。

声明一个数组变量,就在栈上分配了一块内存,用new创建对象,在堆上分配内存了,就将变量初始化成了真正的数组。

下面,分配内存指的是 堆上是否分配内存 ;有没有初始化指的都是数组对象有没有初始化。

在Java当中,如果定义了一个数组,在堆上分配了内存,但对象没有进行初始化。那么数组元素会有一个默认值。

2. 数组的使用

2.1 访问数组

2.2 遍历数组

public class TestDemo {
    public static void main(String[] args) {
        //遍历数组
        int[] array = {1,2,3,4};
        //(!!!)方法一:for循环
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]+" ");
        }
        System.out.println();

        //(!!!)方法二:foreach也叫作增强for循环 (数组中每个元素的类型定义的一个变量:数组名)
        //可以这样理解:遍历array,每拿到一个元素,就存到x中,然后再将x打印出来
        for (int x:array) {
            System.out.print(x+" ");
        }
        System.out.println();
        //方法一和方法二的区别:foreach是拿不到数组下标的,for循环可以拿到数组下标

        //(!!!)方法三:Arrays.toString(数组名)
       /* Java当中有一个工具,可以专门用来操作数组,这个工具叫做Arrays。
        (用它需要导入包:import java.util.Arrays;)*/
        /*toString:返回指定数组的内容的字符串形式
        *         把数组转变为字符串形式,然后返回*/
       String ret = Arrays.toString(array);
       System.out.println(ret);

    }
}

2.3 练习:改变原有数组元素的值

实现一个方法 transform, 以数组为参数, 循环将数组中的每个元素 乘以 2 , 并设置到对应的数组元素上. 例如 原数组为 {1, 2, 3}, 修改之后为 {2, 4, 6}

public class TestDemo2 {
    public static void transform(int[] array){
        for (int i = 0; i < array.length; i++) {
            array[i] *= 2;
        }
    }
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int[] array = new int[n];
        //给数组赋值不能使用foreach,目前知识储备做不到
        //foreach一般用于遍历数组,输出数组元素
       /* for (int x:array) {
            x = scan.nextInt();
        }*/
        //用for循环来做
        for (int i = 0; i < n; i++) {
            array[i] = scan.nextInt();
        }
        transform(array);
        for (int x:array) {
            System.out.print(x+" ");
        }
    }
}

 

总结: 遍历输出数组内容可以考虑for循环foreach,但是给数组初始化用for循环,因为foreach拿不到数组的下标,且目前我的知识储备做不到。

3. 数组是引用类型

3.1 内存分布 

3.1.1 初始JVM的内存分布

JVM对所使用的内存按照功能的不同分为:程序计数器,虚拟机栈,本地方法栈,堆和方法区。

先简单了解一下虚拟机栈和堆。

虚拟机栈:与方法调用相关的一些信息,比如局部变量等。每个方法在执行时,都会先创建一个栈帧。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。

堆:使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2, 3} )。堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销 毁。

方法区:常量,静态变量等。


3.1.2 与C语言的内存分布简单做个对比

C语言也有5大内存分区:栈区,堆区,全局/静态存储区,文字常量区,程序代码区

栈区:局部变量 函数的形参 每一次函数调用都会在栈区上申请空间

堆区:动态内存管理,malloc,free,calloc,realloc

全局/静态存储区:静态变量,全局变量

文字常量区:常量


3.1.3 在Java和C中数组存储位置有什么区别吗?

  • Java中,数组就是对象,是在堆上保存的。对象会有一个地址,地址存在引用变量中,引用变量是一个局部变量,存储在栈上。
  • C语言中,数组在{}内创建,此变量就是局部变量,此时数组就在栈区上;在{}外创建,此变量就是全局变量,此时数组在静态区上。

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

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

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

 

数组是对象,对象存储在堆上,会存在一个地址。

array是引用,存储在栈上,里面放的是对象的地址。

通过地址,就能找到对象,进行打印或修改。

若在main函数里,定义一个数组,main函数结束后,引用变量就会被内存回收,但它指向的对象不一定会被内存回收。对象的回收,是没人引用它。

图解: 

3.3 通过一些题进一步理解引用

题目一:

import java.util.Arrays;

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {1,2,3,4};
        System.out.println(Arrays.toString(array));
        int[] array2 = array;
        array2[1] = 99;
        System.out.println(Arrays.toString(array));
        System.out.println(Arrays.toString(array2));
    }
}

题目二:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {1,2,3,4};
        int[] array2 = {4,5,6,7};
        array = array2;
        System.out.println(Arrays.toString(array));
        System.out.println(Arrays.toString(array2));
    }
}

题目三:

4. 数组的应用(引用/数组名的应用)

传的都是数组名,数组名中存的地址,是对象在堆上的地址,通过数组名就可以找到对象了。

4.1 保存数据

可以用for循环,foreach,Arrays.toString()输出数组内容

4.2 作为函数的参数

在Java中,拿不到栈上的地址,只能拿到堆上的地址,就是这么规定的。

4.2.1  

public class TestDemo {
    public static void func1(int[] array1){
        array1 = new int[10];
    }
    public static void func2(int[] array2){
        array2[0] = 99;
    }
    public static void main(String[] args) {
        int[] array = {1,2,3,4};
        func1(array);
        System.out.println(Arrays.toString(array));
        func2(array);
        System.out.println(Arrays.toString(array));
    }
}

 

4.2.2 交换两个值:

4.3 作为函数的返回值

5. 数组的练习:  Arrays -> 操作 数组相关的 工具类

5.1 数组转字符串:Arrays.toString(数组名) 

Arrays.toString(数组名) :把数组转变为字符串形式,然后返回。

有返回值,需要变量接收。

下面模拟实现一个toString:

public class TestDemo {
    /*自己实现一个toString - myToString
     * 将数组转变为字符串形式,然后输出
    */
    public static String myToString(int[] array){
        if(array == null){//先判断array是不是为null!!!
            return "null";
        }
        String ret = "[";
        for (int i = 0; i < array.length; i++) {
            ret += array[i];
            if(i< array.length-1){
                ret += ",";
            }
        }
       ret += "]";
        return ret;
    }
    public static void main(String[] args) {
        int[] array =null;
        String ret = myToString(array);
        System.out.println(ret);
        int[] array2 ={1,2,3,4};
        String ret2 = myToString(array2);
        System.out.println(ret2);
    }
}

5.2 数组拷贝: Arrays.copyOf()  、  Arrays.copyOfRange()                                         需要拷贝的数组.clone()    、 arraycopy 

5.2.1 Arrays.copyOf(original,new length)

因为new length新的长度int类型的,所以只能是整数倍,不能是小数倍

有返回值,需要变量接收。

看源码:鼠标定位到+ctrl+鼠标左键   或    鼠标定位到ctrl+b

看方法索引:alt+7

5.2.2 Arrays.copyOfRange(original,from,to) 

但它是左闭右开的,最后那个数不在拷贝范围内。此方法支持局部拷贝

有返回值,需要变量接收。

5.2.3 需要拷贝的数组 . clone()

相当于产生一个副本

有返回值,需要变量接收。

5.2.4 arraycopy(要拷贝哪个数组, 从哪个位置开始拷, 往哪个数组里拷, 拷贝到数组的哪个位置, 拷多长)

arraycopy使用特别自由。但是使用前别忘记先定义一个数组来放拷贝后的数据。

没有返回值,不需要变量接收。

5.2.5 自己实现一个数组拷贝

public class TestDemo {
    public static void main(String[] args) {
        int[] array = {1,3,5,7,9};
        int[] array2 = new int[array.length];//Java中 new int[],[]中允许写变量
        for (int i = 0; i < array.length; i++) {
            array2[i] = array[i];
        }
        System.out.println(Arrays.toString(array));
        System.out.println(Arrays.toString(array2));
    }
}

5.3 查找数组中指定元素:顺序查找、二分查找

5.3.1按顺序查找

使用for循环遍历数组,找到返回下标,找不到返回-1

5.3.2 Arrays.binarySearch(要查找的数组,要查找的元素)

二分查找法:只针对有序数组

有返回值,需要变量接收。默认找到返回下标,找不到返回负数

5.3.3 自己实现一个二分查找

二分查找法:只针对有序数组

public class TestDemo {
    public static int binarySearch(int[] array,int k){
        //二分查找
        int left = 0;
        int right = array.length-1;
        while(left<=right){
            int mid = left+((right - left)>>1);
            if(k<array[mid]){
                right = mid - 1;
            }else if(k>array[mid]){
                left = mid +1;
            }else{
                return mid;
            }
        }
        return -1;
    }
    public static void main(String[] args) {
        int[] array = {1,3,5,7,9,13};
        Scanner scan = new Scanner(System.in);
        int k = scan.nextInt();
        int ret = binarySearch(array,k);
        if(ret == -1){
            System.out.println("找不到");
        }else{
            System.out.println("找到了,下标为:"+ret);
        }
    }
}

5.4 数组排序

5.4.1 Arrays.sort

Arrays.sort(数组名)

默认排成升序

没有返回值,不需要变量接收。

 Arrays.sort(数组名,实现了Comparator<T>接口的对象)

5.4.2 冒泡排序

public class TestDemo {
    //数组排序
    //冒泡排序
    public static void bubbleSort(int[] array){
        //趟数
        for (int i = 0; i < array.length-1; i++) {
            boolean flag = true;
            //交换
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j]>array[j+1]){
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    flag = false;
                }
            }
            if(flag == true) {
                return;
            }
        }
    }
    public static void main(String[] args) {
        int[] array = {9,8,7,6,5,4,3,2,1,0};
        bubbleSort(array);
        System.out.println(Arrays.toString(array));

    }
}

5.5 比较两个数组是否相等:Arrays.equals(数组名1,数组名2)

有返回值,需要变量接收。默认相等返回true,不相等返回false

5.6 给数组初始化:Arrays.fill()

没有返回值,不需要变量接收。

5.6.1 全部初始化为同一个值:Arrays.fill(需要初始化的数组,初始化成的值)

5.6.2 部分初始化为同一个值:Arrays.fill(要初始化的数组,from,to,初始化成的值)

左闭右开 

5.7 数组逆序

public class TestDemo {
    public static void reserve(int[] array){
        int left = 0;
        int right = array.length - 1;
        while(left<right){
            int tmp = array[left];
            array[left] = array[right];
            array[right] = tmp;
            left++;
            right--;
        }
    }
    public static void main(String[] args) {
        int[] array = {1, 2, 5, 6, 9, 17, 26, 47, 88, 94};
        reserve(array);
        System.out.println(Arrays.toString(array));
    }
}

6. 二维数组

6.1 二维数组的定义

和一维数组的定义大差不差

6.2 数组的使用

6.2.1 二维数组是特殊的一维数组

6.2.2 一维数组和二维数组在内存中存储的对比图

 6.2.3 遍历二维数组

   //遍历二维数组
    public static void main(String[] args) {
        int[][] array = {{1,2,3},{4,5,6}};
        //1、for循环
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j <array[i].length ; j++) {
                System.out.print(array[i][j]+" ");
            }
            System.out.println();
        }
        System.out.println();
        //2、foreach  增强for循环
        /*(数组中每个元素的类型定义的一个变量:数组名)
        * 一维数组中的每个元素也是一个一维数组*/
        for (int[] arr:array) {
            for (int x:arr) {
                System.out.print(x +" ");
            }
            System.out.println();
        }
        System.out.println();
        //3、Arrays.deepToString(数组名)
        System.out.println(Arrays.deepToString(array));
    }

6.3 不规则的二维数组 

列可以省略,后面可以指定它的列(即每个一维数组的长度)

最后(提醒自己):

一定要将Java和C分隔开,学Java时暂时忘记C,这是两种不同的语言,没必要追究为什么语法不同,因为本来设计就不同。

就像同一个汉字 “我”,在不同地区方言念法不同,这是两种不同的方言,你非要追究为什么在我这“我”是这样念的,在你那就不一样了呢。没有可比性,这本来就是两种不同的方言,它们的共性只有一点,都是语言。

Java和C也是这样,它们是两种不同的计算机语言,本来就不一样。

  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值