Java学习笔记4.——数组(有四个练习题)

Java学习笔记4.——数组

Java基础学习笔记,数组篇



前言

Java基础=计算机基础知识+Java基础语法+运算符+流程控制语句+数组,现在学数组。


提示:以下是本篇文章正文内容,下面案例可供参考

一、数组是什么?

数组,顾名思义,是把数字装起来的东西,不管里面有多少个都称为一组,所以数组英文名叫array。

每一组里面存放的数据类型相同,因为方便存取,看名字也知道存的是什么,计算机也能提高存储效率和运行效率。其实我在想最开始的时候设计的时候是不是与电子有关,只是懂的太少也不知道从何思考,先留个疑问。

1.数组的定义

  • 数据类型 [] 数组名;
    • int[] array;
  • 数组类型 数组名[];
    • int array[];

1.数组初始化的两种方式

初始化就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。
静态初始化
动态初始化

1.静态初始化

完整格式 数组类型[] 数组名 = new 数组类型{元素1,元素2,…};
因为数组中的元素是确定的个数,所以一开始申请就知道需要申请多大的空间,一旦申请好了这个空间就不变化了,然后也同时创建了这个空间的地址值。
那当我们去找这个数组时就需要去访问内存,然后内存通过地址来找这个数组,我们可以直接输出数组他就会打印数组的地址

double heights[] = {};
       System.out.println(age);
       //当然定义这样的数组是没有什么用处的,里面包含了null元素。
       double height[]=new double[0];//创建的是一个没有元素但是长度为0的数组,也不可以添加一个数据

输出结果为[I@10f87f48

[ :代表数组
I :代表int整型,如果是D就是double类型
@ :一个固定格式
10f87f48才是真正的地址值,16进制表示。

注(百度的):然而,当数组的元素类型是对象弓用类型(例如String、 ArrayList等) 时,初始化时必须为数组元素指定一个或多个对象引|用,否则数组元素的默认值将是null。因此,在Java中, int[] a = {}或int[] a = new int[0]不会将数组a的元素初始化为null,因为int不是对象引用类型。

又看了些文章,空数组代表一个对象,数组为0的对象,长度为0;
int [] a= null;
这是空的,就是什么都没有。问了下ai这种在Java中是一种错误的语法,额什么都没有。

为什么直接输出数组名他就会打印数组的地址

因为数组是一个抽象概念,实际存储在内存中,数组名只是一个指向数组在内存中位置的指针。使用数组名的时候就是在访问和操作存储在内存中的数据,所以要查看或者显示数组中的所有数据需要遍历或者指定比如:heights[1];1就是索引

索引的特点从0开始,因为在以前设计之初的时候人们都常从0开始计数。
数组空间里的数据就是通过索引取出来的,如果里面的值都类似于存放常量的区,但是只是类似。
如果数组中的某个值被覆盖了,那原本那个值就不存在了。

数组地址和整型地址的区别

既然数组有地址,那么整型变量在内存中也会有地址,可以通过变量名来引用他所对应的地址,编译器自动管理变量的内存地址所以我们对地址就了解得很陌生
整数变量是单个数据的存储,数组的多个数据的存储,数组中每个元素都是连续存储的,也都有自己的地址。
只不过数组地址代表那个地方还有很多地址,不能像变量一样使用,还需要指定。

数组遍历
数组遍历:取出所有数据的过程

public class ArrayTest1 {
    public static void main(String[] args) {
        int [] age = new int[]{1,2,3,4,5};
        for (int i = 0; i < age.length; i++) {
            System.out.println(age[i]);
        }
    }
}
数组遍历小案例

遍历数组求和,

public class ArrayTest1 {
    public static void main(String[] args) {
        int [] age = new int[]{1,2,3,4,5};
        int sum =0;
        for (int i = 0; i < age.length; i++) {
            sum += age[i];
        }
        System.out.println(sum);
    }
}

统计个数
定义一个数组,存储1,2,3,4,5,6,7,8,9,10
遍历数组得到每一个元素,统计数组里面一共有多少个能被3整除的数字.

public class ArrayTest1 {
    public static void main(String[] args) {
//        统计个数
//定义一个数组,存储1,2,3,4,5,6,7,8,9,10
//遍历数组得到每一个元素,统计数组里面一共有多少个能被3整除的数字.
        int [] age = new int[]{1,2,3,4,5,6,7,8,9,10};
        int count =0;
        for (int i = 0; i < age.length; i++) {
            if (age[i]%3==0){
                count++;
            }
        }
        System.out.println(count);
    }
}

变化数据
定义一个数组,存储1,2,3,4,5,6,7,8,9,10
遍历数组得到每-一个元素。
要求:
1,如果是奇数,则将当前数字扩大两倍
2,如果是偶数,则将当前数字变成二分之-

public class ArrayTest1 {
    public static void main(String[] args) {
//        变化数据
//定义一个数组,存储1,2,3,4,5,6,7,8,9,10
//遍历数组得到每-一个元素。
//要求:
//1,如果是奇数,则将当前数字扩大两倍
//2,如果是偶数,则将当前数字变成二分之-
        int [] age = new int[]{1,2,3,4,5,6,7,8,9,10};
        int count =0;
        for (int i = 0; i < age.length; i++) {
            if (age[i]%2==0){
                age[i] = age[i]/2;
            }else {
                age[i] *= 2;
            }
            System.out.println(age[i]);
        }
    }
}

一个循环尽量只做一件事情,所以打印这个事情可以单独放一个循环里来做。

2.动态初始化

格式:
数据类型[] 数组名 = new 数据类型[数组长度];
int[] a = new int[5];
这种时候是不知道具体的值,但是知道数组的大小就可以使用这种,这时候虚拟机给出默认的初始化值,就不需要我们手动的初始化,但是静态的初始化我们是手动的初始化值。

数组默认初始化的规律

整数类型:默认初始化值0
小数类型:默认初始化值0.0
字符类型:默认初始化值’/u0000’空格
布尔类型:默认初始化值false
引用数据类型:默认初始化值 null

2.数组常见问题

数组索引越界

二、数组练习

1.求和

求数组里的最大值,同理最小值一样

public class ArrayTest2 {
    public static void main(String[] args) {
        int [] a = new int[]{33,5,22,44,55};
        int max=a[0];
        //因为i=0时第一次是自己跟自己比较,效率偏低没有最大化用到极致
        for (int i = 1; i < a.length; i++) {
            if (a[i]>max){
                max = a[i];
            }
        }
        System.out.println(max);
    }
}

2.求平均值

需求:生成10个1~100之间的随机数存入数组,求他们的平均值

public class ArrayTest3 {
    public static void main(String[] args) {
        //遍历数组求和
        //需求:生成10个1~100之间的随机数存入数组,求他们的平均值。
        //分析1:数组大小10,随机数存入
        int array[] = new int[10];
        Random r = new Random();
        for (int i = 0; i < array.length; i++) {
            int a = r.nextInt(100)+1;
            array[i] = a;
        }
        //分析2:求出所有数据之和
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
            sum += array[i];
        }
        System.out.println(sum);
        //分析3:所有数的平均数,和/10
        int average = sum/10;
        //分析4:统计比平均值小的个数
        int count = 0;
        for (int i = 0; i < array.length; i++) {
            if (array[i]<average){
                count++;
            }
        }
        System.out.println(count);
    }
}

3.交换数据

//需求:定义一个数组,存入1,2,3,4,5。 按照要求交换索引对应的元素。
//交换前: 1,2,3,4,5
//交换后: 5,2,3,4,1

public class ArrayTest4 {
    public static void main(String[] args) {
        //需求:定义一个数组,存入1,2,3,4,5。 按照要求交换索引对应的元素。
        //交换前: 1,2,3,4,5
        //交换后: 5,2,3,4,1
        int array[] = {1,2,3,4,5};
        //分析1:从前往后交换,被交换的值需要被保存
        int temp = 0;
        //可以改成i<j,然后去掉if,偶数的话i<j也能交换,奇数的话中间那个数就没有被交换的必要了。
        for (int i = 0,j=array.length-1; i < array.length && j>=0; i++,j--) {
            if (i<=j){
                temp = array[j];
                array[j]=array[i];
                array[i]=temp;
            }
        }
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}

4.随机交换数据

需求:定义一个数组,存入1~5。要求打乱数组中所有数据的顺序。
考的知识点:

知识点1:定义数组并静态初始化
知识点2:随机考的是Random函数的使用
知识点3:随机打乱,考的是索引
知识点4:用for循环实现随机,考的是for循环的机制
知识点5:交换数据,考验对数据的覆盖这一块,需要temp保存中间值

package itheima;

import java.util.Random;

public class ArrayTest5 {
    public static void main(String[] args) {
        //需求:定义一个数组,存入1~5。要求打乱数组中所有数据的顺序。
        //1.定义数组,存入1~5
        int a[] = new int[]{1,2,3,4,5};
        //2.打乱数据,需要随机数0~4,因为数组只有这么长
        //3.是先随机选择一个数与之交换,所以随机数在循环里
        //4.按照顺序进行随机交换,可能第一轮就与第四个数据交互,第二轮就与第一个数据交换。
        Random r = new Random();
        for (int i = 0; i < a.length; i++) {
            int b = r.nextInt(a.length);
            int temp = a[i];
            a[i] = a[b];
            a[b] = temp;
        }
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }
    }
}

三、数组的内存图

1.java内存分配

在这里插入图片描述
听说最开始堆和方法是这样的,后来方法独立出来,最后来方法区就被拆了
在这里插入图片描述
JDK8的时候方法区就取消了,增加了元空间,方法区中的多种功能也进行拆分放到了堆和元空间中了。


  • 方法运行时使用的内存,方法运行时进入栈中执行,执行完根据先进后出的规则依次释放出栈。
    方法没被运行就不会使用这个栈。

  • new创建的东西都存储在堆内存中,因为new时需要申请一个空间,生成的空间有空间地址,空间用完了可以释放。所以堆区作用主要是申请和释放资源。

数组内存图的使用过程可以看阿站黑马数组内存图的视频
栈中方法里创建数组就是在堆区中申请空间,所以栈中保存的是地址指向堆区,所以计算机控制器里的PC保存的就是程序流程控制语句的这种地址吧!这是直接寻找方式吧!

数组可以指向同一个堆空间,就像方法里的引值调用。

四、二维数组

二维数组就是一个盒子里面装了两个数组,两个数组分别装了不同的数据,长度也可以不同。
二维数组的定义和前面一样,也有静态初始化和动态初始化。

二维数组的维度是行和列,行一维,列一维,所以不是说是只有两个数组的才是二维数组。它的维度在于行和列。

int[][] array = new int[][]{{数据1,数据2...},{数据x,数据y,...}};
int[][] array2 = {{数据1,数据2...},{数据x,数据y,...}};
//这种也是允许的,只是代码第二个数组就没啥意思了。
int[][] array3 = {{1,2,3,34,5},{}};

public static void main(String[] args) {
        int[][] array3 = {
                {1,2,3,4},
                {5,6,7,8,9,10}
        };
        //遍历数组,获取一维,再打印一维数组里的数据
        for (int i = 0; i < array3.length; i++) {//这是一维的,长度是2
            for (int j = 0; j < array3[i].length; j++) {
                System.out.print(array3[i][j]+" ");
            }
            System.out.println();
        }
    }

1.二维数组在内存中的分配

因为我们知道二维数组赋值也是一个它的地址,然后这个二维数组里放了i个(第一个中括号)一维数组的地址,然后第二个中括号放的是第i个一维数组中的有j个数据。在这里插入图片描述

int[][] array = new int[2][3]这就是一个二行三列的矩阵

所以后面有两种定义方法可以看看。

1.特殊情况1

//代表有两个一维数组,一维数组里还没有添加数据,情况1,此时1维数组连地址都没有,是null
        int[][] array4 = new int[2][];
//        int[] arr1 = {1,2,3};
//        int[] arr2 = {4,5,6,7,8};
//        array4[0] = arr1;
//        array4[1] = arr2;
        //代表第一个一维数组里面的地址是arr1的地址,所以它就会指向arr1
//        for (int i = 0; i < array4.length; i++) {//这是一维的,长度是2
//            for (int j = 0; j < array4[i].length; j++) {
//                System.out.print(array4[i][j]+" ");
//            }
//            System.out.println();
//        }
System.out.println(array4[0]);//这个输出结果是null

此时的状态就是这样,所以输出结果是null
在这里插入图片描述

第一种情况是定义之后,只定义了二维数组有几个一维数组,但是一维数组没有定义是null,这个时候创建一维数组再把地址分别赋值给二维的一维数组,这种可以自定义不用被固定在具体的矩阵行列里。

2.特殊情况2

假如赋值了,就是下面这种

int[][] array4 = new int[2][3];

代表两个一维数组的长度都是3,并且这时一维数组已经建立起来了,其值已经被系统自动初始化了,且输出System.out.println(array5[0]);结果是第0行的一维数组的地址。
遍历这个数组就是输出二行三列的0.
在这里插入图片描述

//情况二
        int[][] array5 = new int[2][3];
        int[] arr3 = {1,2};
        int[] arr4 = {4,5,6,4};
        //分别把这两个一维数组的地址传给二维数组
        array5[0] = arr3;
        array5[1] = arr4;
        for (int i = 0; i < array5.length; i++) {//这是一维的,长度是2
            for (int j = 0; j < array5[i].length; j++) {
                System.out.print(array5[i][j]+" ");
            }
            System.out.println();
        }
        System.out.println(array5[0]);
    }

这个时候一维数组的长度也是不受限制的,因为其地址值都已经变了,而原来的那个地址值也就消失了,因为没有使用的价值也没有存在的变量节约空间。

1和2的区别如下:

第一种是二维数组只是说有,但是没有定义一维数组地址值是null,所以可以定义一维数组赋值给二维数组。
第二种是二维数组已经定好了一维数组和大小,此时已经存在了一维数组地址一维数组已经真实存在了,但是一维数组的地址值被其他一维数组值覆盖了,这时候原来的一维数组地址就不再了。


总结

数组就是存放数据的一个容器叫做Array,可以先用new在堆区中申请一个数组对象,然后把数据放进去,这种就是静态初始化。

或者申请一个大小为x的数组对象,不把数据放进去,这时候系统会自动初始化,这种是动态初始化,根据申请的数组类型不同,系统默认的初始化值也会不同。

栈是方法运行时的时候才会有的。

二维数组就相当于一个箱子里放了两个数组(假如你定义了三个1一维数组那就是三个。):

  • 特殊情况1:就是代表说明了这个箱子是存放两个数组的箱子,但是里面的箱子还没有放进来,也不知道那两个一维箱子有多大。
  • 特殊情况2:就是说明大箱子里已经放了两个一维箱子进去了,然后觉得放的这两个一维箱子不合适,就重新换了两个箱子放进去,所以原本的箱子就只有从里面拿出来,不放在内存里自然就不见了。
    • 至于说为什么装进去不拿出来,那就成了4个一维数组了,与定义描述的两个不符合。就像你买东西说你买的东西有两个组件组成,回家发现里面有四个组件组成,与卖家说的不一样这时候可以告他讹他一笔。

定义就是说一不二,说是什么就是什么,如果不是那就不是这个定义。
所以不需要在多想了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专注技术200年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值