相关链接
目录
- 搭建maven项目运行,参考pom.xml 用junit测试类执行代码
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
Part4 数组
- 数组概念
- 存储同一种数据类型,多个元素的容器。
- 数组既可以存储基本数据类型,也可以存储引用数据类型。
- 数组的定义格式
- 格式1:数据类型[] 数组名;
- 格式2:数据类型 数组名[];
注意:这两种定义做完了,数组中是没有元素值的。如何对数组的元素进行初始化呢?
数组的概述
- 需求:现在需要统计某公司员工的工资情况,例如计算平均工资、找到最高工资等。假设该公司有80名员工,用前面所学的知识,程序首先需要声明80个变量来分别记住每位员工的工资,然后在进行操作,这样做会显得很麻烦。为了解决这种问题,Java就提供了数组供我们使用。
- 那么数组到底是什么呢?有什么特点呢?通过上面的分析:我们可以得到如下两句话:
- 数组是存储多个变量(元素)的东西(容器)
- 这多个变量的数据类型要一致
1 数组的初始化
- 数组的初始化
- Java中的数组必须先初始化,然后才能使用。
- 就是为数组中的数组元素分配内存空间,并为每个数组元素赋值。
- 数组的初始化有以下两种方式
动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。 int[] arr = new int[3]; arr[0]=2; arr[1]=5; arr[2]=7; 静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度。 //完整写法 int[] arr = new int[]{2,5,7}; //其他写法 不推荐 //解释:定义了一个int类型的数组,这个数组中可以存放3个int类型的值。结果相同,但推荐用第一种写法。 //一般将实例名(这里指arr)放在等号左侧相邻的位置,否则容易引起歧义(变量名到底是 arr 还是 arr[] ?)。 int arr[] = new int[]{2,5,7}; //简化写法 不推荐 int[] arr = {2,5,7};
- 数组遍历的快捷键 => 见 IDEA常见问题记录 JDK8 1.1.1 数组[ ]
1.1 动态初始化
-
动态初始化
- 给出数组的长度,初始值由系统为数组分配。
-
格式
- 标准写法:
数据类型[] 数组名 = new 数据类型[数组长度];
- 其他写法:
数据类型 数组名[] = new 数据类型[数组长度];
(不推荐)
- 标准写法:
-
实例
- 解释:定义了一个int类型的数组,这个数组中可以存放3个int类型的值,系统自定分配初始值,int类型初始值为0。
int[] arr = new int[3]; int arr[] = new int[3]; //不推荐
-
数组长度
- 数组中元素的个数。3个。
-
获取元素的格式:
- 数组名[索引] => arr[0] = 0;
- 索引编号从0开始,最大的编号是数组的长度 -1 => new int[3] 索引最大编号为 2
-
动态初始化的值
动态初始化数据类型 默认值 备注 byte,short,int,long 0 float double 0.0 char ‘\u0000’ \u表示unicode编码,\u0000 表示Unicode编码中的 null boolean false 引用类型 null
案例代码一 动态初始化
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 数组:存储同一种数据类型的多个元素的容器。
*
* 定义格式:
* A:数据类型[] 数组名;
* B:数据类型 数组名[];
* 举例:
* A:int[] a; 定义一个int类型的数组,数组名是a
* B:int a[]; 定义一个int类型的变量,变量名是a数组
*
* 数组初始化:
* A:所谓初始化,就是为数组开辟内存空间,并为数组中的每个元素赋予初始值
* B:我们有两种方式对数组进行初始化
* a:动态初始化 只指定长度,由系统给出初始化值
* b:静态初始化 给出初始化值,由系统决定长度
*
* 动态初始化:
* 数据类型[] 数组名 = new 数据类型[数组长度];
*/
public void OperatorDemo1() {
//数据类型[] 数组名 = new 数据类型[数组长度];
int[] arr = new int[3];
/*
* 左边:
* int:说明数组中的元素的数据类型是int类型
* []:说明这是一个数组
* arr:是数组的名称
* 右边:
* new:为数组分配内存空间
* int:说明数组中的元素的数据类型是int类型
* []:说明这是一个数组
* 3:数组的长度,其实就是数组中的元素个数
*/
}
}
案例代码二 动态初始化练习 获取数组中的元素
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 数组:存储同一种数据类型的多个元素的容器。
*
* 定义格式:
* A:数据类型[] 数组名;(推荐的使用方式)
* B:数据类型 数组名[];
*
* 举例:
* int[] arr; 定义了一个int类型的数组,数组名是arr
* int arr[]; 定义了一个int类型的变量,变量名是arr数组
*
* 数组初始化:
* A:所谓的初始化,其实就是为数组开辟内存空间,并为数组中的每个元素赋予初始值。
* B:如何进行初始化呢?我们有两种方式对数组进行初始化
* a:动态初始化 只给出长度,由系统给出初始化值
* b:静态初始化 给出初始化值,由系统决定长度
*
* 动态初始化:
* 数据类型[] 数组名 = new 数据类型[数组长度];
*/
public void OperatorDemo2() {
//数据类型[] 数组名 = new 数据类型[数组长度];
int[] arr = new int[4];
//遍历arr数组,并给数组中的每个元素赋值(除了最后一个)
for (int i = 0; i < arr.length-1; i++) {
arr[i] = i * 5 - 1;
}
/*
* 左边:
* int:说明数组中的元素的数据类型是int类型
* []:说明这是一个数组
* arr:是数组的名称
* 右边:
* new:为数组分配内存空间
* int:说明数组中的元素的数据类型是int类型
* []:说明这是一个数组
* 3:数组的长度,其实就是数组中的元素个数
*/
//输出数组名
System.out.println("arr:" + arr); //[I@50134894 ,只要new出来的arr没被JVM的gc回收掉,这个new出来的对象地址就一直是这个
//通过输出数组名,我们得到了一个数组的地址值(也叫指针)(Java通过这个指针找到堆中数组存放的位置),但是这个值对我们来说没有意义
//我要获取的是数组中的元素值,能不能获取到呢?能
//怎么获取呢?不同担心,Java已经帮你想好了
//其实数组中的每个元素是有编号的,编号从0开始,最大的编号是数组的长度-1
//通过数组名和编号的配合使用我们就可以获取数组中指定编号的元素值
//怎么配合的呢?编号的专业叫法:索引
//获取元素的格式:数组名[索引]
System.out.println("arr[0]:" + arr[0]);//-1
System.out.println("arr[1]:" + arr[1]);//4
System.out.println("arr[2]:" + arr[2]);//9
System.out.println("arr[2]:" + arr[3]);//0
}
}
- 下面按照数据库SQL的角度来理解一下整个过程
-
第一步:创建对象 int[] arr = new int[4];
- a.堆中创建了arr对象,数组空间为4,初始化时程序员只指定数组长度,由系统为数组元素分配初始值(即0)。分配对象时拿到了一个地址值
[I@50134894
,可以通过这个地址值准确定位到此次new int[4]
对象 - b.栈中存储对象实例(局部变量),通过实例名可以找到对象在堆中的地址值
[I@50134894
,进而找到堆中的对象
- a.堆中创建了arr对象,数组空间为4,初始化时程序员只指定数组长度,由系统为数组元素分配初始值(即0)。分配对象时拿到了一个地址值
-
第二步:遍历arr数组,并给数组中的每个元素赋值(除了最后一个)
for (int i = 0; i < arr.length-1; i++) { arr[i] = i * 5 - 1; }
- 此时除了arr[3]使用默认值0,arr数组前三个元素都已手动赋值
- 此时除了arr[3]使用默认值0,arr数组前三个元素都已手动赋值
-
第三步: 输出地址值 System.out.println(“arr:” + arr);
- 通过实例名找到地址值,并打印,结果为
[I@50134894
- 通过实例名找到地址值,并打印,结果为
-
- 第四步:获取数组对象的元素值 System.out.println(“arr[0]:” + arr[0]);
- 这里可以按照sql的逻辑理解,底层做了类似这样的查询(实际可能更复杂一点,原理类似)
- a.获取地址值
select adress --=>获取地址值 [I@50134894,这个地址值作为 from 的表名传到下一个sql中 from 栈 where instanceName ='arr'
- b.获取arr数组索引为0的元素值
select value --arr[0]的实际值,即index=0时,value列的值,可见该值为-1 from [I@50134894 --arr对象的地址值,通过这个地址定位到唯一的对象 where index = 0; --arr对象包含多个元素,根据索引可以定位到表中某一行数据(因为索引也是主键,不重复)
1.2 数组内存结构
Java 程序在运行时,需要在内存中的分配空间。为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
- 栈:存储局部变量,对象实例的地址
- 堆:存储new出来的东西,对象实例
- 方法区:包含类从磁盘到内存的整个生命周期,编译>加载>连接>初始化>使用>卸载
- 本地方法区:和系统相关,实现Java应用与Java外面环境的交互,本地方法提供接口,实现体在外面其他语言。在windows中就是使用windows系统语言实现Java代码
- 数组的内存图
- 需要掌握一个数组在内存中的变化,其他的内存图能看懂即可
- 举例 => What does a Java array look like in memory?
- 数组与对象的处理方式相同,因此通过一个实例:调用方法m1时的过程,来观察数组及其引用的存储位置。
class A { int x; int y; } ... public void m1() { int i = 0; m2(); } public void m2() { A a = new A(); }
- 当m1被调用的时候,栈帧Frame-1被创建并push到栈中,同时局部变量i也在栈帧Frame-1内创建。
- 然后,m2方法在m1方法内部被调用,栈帧Frame-2被创建并push到栈中,在m2方法中,一个新的对象A在堆中被创建,而它的引用则被put到栈帧Frame-2里;
案例代码三 两个数组的内存图
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 定义两个数组,分别输出数组名及元素。然后分别给数组中的元素赋值,分别再次输出数组名及元素。
*/
public void OperatorDemo3() {
//定义两个数组
int[] arr = new int[2];
int[] arr2 = new int[3];
//分别输出数组名及元素
/*
arr:[I@50134894
arr[0]:0
arr[1]:0
*/
System.out.println("arr:" + arr);
System.out.println("arr[0]:" + arr[0]);
System.out.println("arr[1]:" + arr[1]);
System.out.println("--------------");
/*
arr2:[I@2957fcb0
arr2[0]:0
arr2[1]:0
arr2[2]:0
*/
System.out.println("arr2:" + arr2);
System.out.println("arr2[0]:" + arr2[0]);
System.out.println("arr2[1]:" + arr2[1]);
System.out.println("arr2[2]:" + arr2[2]);
System.out.println("--------------");
//然后分别给数组中的元素赋值
arr[1] = 100;
arr2[0] = 200;
arr2[1] = 300;
//分别再次输出数组名及元素
/*
arr:[I@50134894
arr[0]:0
arr[1]:100
*/
System.out.println("arr:" + arr);
System.out.println("arr[0]:" + arr[0]);
System.out.println("arr[1]:" + arr[1]);
System.out.println("--------------");
/*
arr2:[I@2957fcb0
arr2[0]:200
arr2[1]:300
arr2[2]:0
*/
System.out.println("arr2:" + arr2);
System.out.println("arr2[0]:" + arr2[0]);
System.out.println("arr2[1]:" + arr2[1]);
System.out.println("arr2[2]:" + arr2[2]);
System.out.println("--------------");
}
}
- 案例三代码内存图解
案例代码四 两个数组指向同一个堆内存的内存图
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 定义两个数组,先定义一个数组,赋值,输出。然后定义第二个数组的时候把第一个数组的地址赋值给第二个数组。
* 然后给第二个数组赋值,再次输出两个数组的名及元素。
*/
public void OperatorDemo4() {
//先定义一个数组
int[] arr = new int[3];
//赋值
arr[0] = 100;
arr[1] = 200;
arr[2] = 300;
//输出
/*
arr:[I@50134894
arr[0]:100
arr[1]:200
arr[2]:300
*/
System.out.println("arr:" + arr);
System.out.println("arr[0]:" + arr[0]);
System.out.println("arr[1]:" + arr[1]);
System.out.println("arr[2]:" + arr[2]);
System.out.println("--------------");
//然后定义第二个数组的时候把第一个数组的地址赋值给第二个数组
int[] arr2 = arr;
//然后给第二个数组赋值
arr2[0] = 111;
arr2[1] = 222;
arr2[2] = 333;
//再次输出两个数组的名及元素
/*
arr:[I@50134894
arr[0]:111
arr[1]:222
arr[2]:333
*/
System.out.println("arr:" + arr);
System.out.println("arr[0]:" + arr[0]);
System.out.println("arr[1]:" + arr[1]);
System.out.println("arr[2]:" + arr[2]);
System.out.println("--------------");
/*
arr2:[I@50134894
arr2[0]:111
arr2[1]:222
arr2[2]:333
*/
System.out.println("arr2:" + arr2);
System.out.println("arr2[0]:" + arr2[0]);
System.out.println("arr2[1]:" + arr2[1]);
System.out.println("arr2[2]:" + arr2[2]);
}
}
- 案例四代码内存图解
案例代码五 intern方法与字符串
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 练习5:字符串地址判断练习
*/
public void OperatorDemo5() {
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
//【true】:在程序运行时,会将s1创建的字符串“abc”放到方法区的运行时常量池(Runtime Constant Pool)中,
// 再创建s2时,会到运行时常量池(Runtime Constant Pool)中去找有没有“abc”,然后将“abc”赋值给s2,所输出为true。
System.out.println(s1 == s2);
//【false】:使用new关键字创建字符串,会将“abc”放到Java堆中,
//他们分别在不同的存储区域,所以地址也是不同的,所以输出为false,
System.out.println(s1 == s3);
//【true】:这个方法是本地(native)方法,是将s3指向的“abc”放到常量池中,
// 但是常量池中存在“abc”,所以s3.intern(),s1,s2指向的是同一个常量池中的“abc”。
System.out.println(s1 == s3.intern());
}
}
1.3 静态初始化
- 数组的静态初始化:给出初始化值,由系统决定长度。
- 格式
- 标准写法:
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3,...};
- 其他写法:
数据类型 数组名[] = new 数据类型[]{元素1,元素2,元素3,...};
(不推荐) - 简化写法:
数据类型[] 数组名 = {元素1,元素2,元素3,...};
(不推荐)
- 标准写法:
- 实例
- 解释:定义了一个int类型的数组,这个数组中可以存放3个int类型的值,并且值分别是2,5,7。
int[] arr = new int[]{2,5,7}; int arr[] = new int[]{2,5,7}; //不推荐 int[] arr = {2,5,7}; //不推荐
- 数组长度
- 数组中元素的个数。3个。
- 获取元素的格式:
- 数组名[索引] => arr[0] = 2;
- 索引编号从0开始,最大的编号是数组的长度 -1 => new int[3] 索引最大编号为 2
案例代码六 静态初始化数组
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 静态初始化:给出数组中的元素值,由系统决定数组的长度。
*
* 格式:
* 数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3,...};
*
* 举例:
* int[] arr = new int[]{1,2,3};
*
* 简化的格式:
* 数据类型[] 数组名 = {元素1,元素2,元素3,...};
* 简化格式的代码:
* int[] arr = {1,2,3};
*/
public void OperatorDemo6() {
//静态初始化一个数组
int[] arr = {1, 2, 3};
//输出数组名和元素值
/*
arr:[I@50134894
arr[0]:1
arr[1]:2
arr[2]:3
*/
//在栈中存储了arr实例名对应在 堆中的(实例对象)内存地址 arr:[I@50134894
System.out.println("arr:" + arr);
//在堆中存储了arr实例对象索引为0的 实际值1
System.out.println("arr[0]:" + arr[0]);
//在堆中存储了arr实例对象索引为1的 实际值2
System.out.println("arr[1]:" + arr[1]);
//在堆中存储了arr实例对象索引为2的 实际值3
System.out.println("arr[2]:" + arr[2]);
}
}
1.4 二维数组
- 二维数组:知道有这个东西就可以
- 其实就是元素为一维数组的数组
- 格式:
- 动态初始化: m 表示的是二维数组中一维数组的个数;n 表示的是一维数组中的元素个数
- 标准写法:
数据类型[m][n] 数组名 = new 数据类型[m][n];
- 其他写法:
数据类型[m] 数组名[n] = new 数据类型[m][n];
(不推荐) - 其他写法:
数据类型 数组名[m][n] = new 数据类型[m][n];
(不推荐)
- 标准写法:
- 静态初始化
- 标准写法:
数据类型[][] 数组名 = new 数据类型[][]{{元素...},{元素...},{元素...},...};
- 简化格式:
数据类型[][] 数组名 = {{元素...},{元素...},{元素...},...};
- 标准写法:
- 动态初始化: m 表示的是二维数组中一维数组的个数;n 表示的是一维数组中的元素个数
- 动态初始化实例
- 解释:在Java中我们只能有一个一维数组。2维数组只是1维数组的数组。
动态初始化一个数组长度为3的二维数组,二维数组中的元素为3个长度分别为3,5,4的动态初始化的一维数组。
int[ ][ ] arr = new int[3][ ]; //int[ ] arr[ ] = new int[3][ ];//不推荐 //int arr[ ][ ] = new int[3][ ];//不推荐 arr[0] = new int[3]; arr[1] = new int[5]; arr[2] = new int[4]; arr[0][0] = 1; arr[0][1] = 2; arr[0][2] = 3;
- 解释:在Java中我们只能有一个一维数组。2维数组只是1维数组的数组。
- 图解动态初始化实例
- 静态初始化实例
- 解释:静态初始化一个二维数组,其中包含4个一维数组
int[][] arr = new int[][]{{1, 2, 3}, {10, 20, 30}, {100, 200}, {Integer.valueOf('s'), Integer.valueOf('a')}}; //int[][] arr = {{1, 2, 3}, {10, 20, 30}, {100, 200}, {Integer.valueOf('s'), Integer.valueOf('a')}};//不推荐
- 数组长度
- 数组中元素的个数。外层为3个,内层分别为3个,5个,4个。
- 获取元素的格式:
- 数组名[索引] => arr[0][0] = 0;
- 索引编号从0开始,最大的编号是数组的长度 -1 => new int[3] 索引最大编号为 2
案例代码七 二维数组元素获取与遍历
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 二维数组的元素获取与遍历
*/
public void OperatorDemo7() {
//静态初始化一个二维数组,其中包含4个一维数组
int[][] arr = new int[][]{
{1, 2, 3},
{10, 20, 30},
{100, 200},
{Integer.valueOf('s'), Integer.valueOf('a')}
};
//直接获取元素值
//arr[0]:[I@50134894 =>
//arr[0]元素为一维数组的实例名,直接打印实例名得到的是对象在堆中的内存地址;
System.out.println("arr[0]:" + arr[0]);
//arr[1]:[I@2957fcb0 =>
//arr[1]元素为一维数组的实例名,直接打印实例名得到的是对象在堆中的内存地址;
System.out.println("arr[1]:" + arr[1]);
//arr[2]:[I@1376c05c =>
//arr[2]元素为一维数组的实例名,直接打印实例名得到的是对象在堆中的内存地址;
System.out.println("arr[2]:" + arr[2]);
//arr[0][2]:1 => 数组 {1, 2, 3} 中第一个元素值为1;
System.out.println("arr[0][2]:" + arr[0][0]);
//arr[0][2]:2 => 数组 {1, 2, 3} 中第二个元素值为2;
System.out.println("arr[0][2]:" + arr[0][1]);
//arr[1][0]:10 => 数组 {10, 20, 30} 中第1个元素值为10;
System.out.println("arr[1][0]:" + arr[1][0]);
//遍历数组:首先遍历外层,获取二维数组中的每一个元素
for (int i = 0; i < arr.length; i++) {
//arrInner为外层数组的元素,这个元素为一维数组
int[] arrInner = arr[i];
//继续遍历这个一维数组arrInner
for (int j = 0; j < arrInner.length; j++) {
//取出一维数组中的每一个int类型元素,并赋值给变量a,并打印这个元素值
int a = arrInner[j];
/*
1
2
3
-----
10
20
30
-----
100
200
-----
115 ('s')对应码表值为115
97 ('a')对应码表值为97
-----
*/
System.out.println(a);
}
System.out.println("-----");
}
}
}
2 数组两个常见的小问题
2.1 索引越界异常 ArrayIndexOutOfBoundsException
如何产生的呢?我们访问了不存在的索引
2.2 空指针异常 NullPointerException
如何产生的呢?null是指不再指向堆内存的数据,而我们还在访问堆内存的数据
案例代码八 数组两个常见的小问题
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 数组两个常见小问题:
* ArrayIndexOutOfBoundsException:数组索引越界异常
* 如何产生的呢?我们访问了不存在的索引。
*
* NullPointerException:空指针异常
* 如何产生的呢?null是指不再指向堆内存的数据,而我们还在访问堆内存的数据
*/
public void OperatorDemo8() {
//静态初始化一个数组,元素类型为int
int[] arr = new int[]{1, 2, 3};
//访问数组中不存在的元素:第4个元素
//索引越界异常:java.lang.ArrayIndexOutOfBoundsException: 3
try {
System.out.println(arr[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常:访问了不存在的索引。");
e.printStackTrace();
}
System.out.println("----------------------");
//引用数据类型:类,接口,数组
//常量:null,它是可以赋值给引用数据类型的,表示该引用不再指向堆内存的数据
arr = null;
try {
System.out.println(arr[1]);
} catch (NullPointerException e) {
System.out.println("空指针异常:null是指不再指向堆内存的数据,而我们还在访问堆内存的数据。");
e.printStackTrace();
}
}
}
3 数组练习题
3.1 数组操作之 遍历数组
见 => No.1.1_1 IDEA常见问题记录JDK8 1.1.1 数组[]
3.2 数组操作之 获取最值
案例代码九 数组操作之 获取最值
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 需求:数组获取最值(获取数组中的最大值最小值)
*/
public void OperatorDemo9() {
//定义数组
int[] arr = {12, 98, 45, 101, 73, 60};
//定义参照物
int max = arr[0];
//记录元素位置
int order = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
//索引从0开始计数,所以要加1
order = i + 1;
//将新的最大值赋值给变量max
max = arr[i];
}
}
//arr数组的最大值为第:【6】个,值为:【101】
System.out.println("arr数组的最大值为第:【" + order + "】个,值为:【" + max + "】");
}
}
3.3 数组操作之 评委打分
由于Junit测试类不能执行Scanner键盘录入,需要新建一个类class
案例代码九 数组操作之 评委打分
package com.itheima;
import java.util.Arrays;
import java.util.Scanner;
/**
* @author GroupiesM
* @date 2021/2/22
*/
public class OperatorDemo10 {
/**
* 需求:在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。
* 选手的最后得分为:去掉一个最高分和一个最低分后 的4个评委平均值。
* 请写代码实现。(不考虑小数部分)
*
* 分析:
* A:定义一个长度为6的数组
* B:评委打分的数据采用键盘录入实现
* C:写代码获取数组的最大值(最高分)
* D:写代码获取数组的最小值(最低分)
* E:写代码求数组中的元素和(总分)
* F:平均分:(总分-最高分-最低分)/(arr.length-2)
* G:输出平均分即可
*/
public static void main(String[] args) {
//定义一个长度为6的数组
int[] arr = new int[6];
//评委打分的数据采用键盘录入实现
Scanner sc = new Scanner(System.in);
for (int i = 0; i < arr.length; i++) {
System.out.println("请输入第" + (i + 1) + "个评委给出的分数:");
arr[i] = sc.nextInt();
}
//调用getAverage方法获取平均分数
double avg = getAverage(arr);
System.out.println("评委给出的平均分为:" + avg);
//也可以直接使用数组中的方法获取平均值,但这种方法不能去掉最大最小值后再取平均
System.out.println(Arrays.stream(arr).average());
}
//定义方法,传入int类型数组,返回平均分
public static double getAverage(int[] arr) {
//写代码获取数组的最大值(最高分)
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
System.out.println("评委给出分数中的最高分为:" + max);
//写代码获取数组的最小值(最低分)
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
System.out.println("评委给出分数中的最低分为:" + min);
//写代码求数组中的元素和(总分)
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println("评委给出总分为:" + min);
//平均分:(总分-最高分-最低分)/(arr.length-2)
//这里将int转为double类型,以获取精确平均分,否则只能保留到个位分数
double avg = Double.valueOf(sum - max - min) / (arr.length - 2);
return avg;
}
}
3.3 数组操作之 不死神兔
网上很多地方能搜到这道题《不死神兔》,但是答案都是错的,比如=>这篇博客。而原题目看这里 =>斐波那契数列是"假设一对刚出生的小兔一个月后就能长成大兔,再过一个月就能生下一对小兔,并且此后每个月都生一对小兔,一年内没有发生死亡,问:一对刚出生的兔子,一年内繁殖成多少对兔子?"。可以清楚地看到原题要求兔子2个月成年,而网上题目大部分写的3个月成年,由于需求不同也导致了结果大相径庭。
2个月成年的题目已经有很多答案了,这里算一下三个月成年到底有多少只,并不打算推导数学公式,仅用Java二维数组迭代循环的方式算出结果。首先总结规律,可以观察到从第四个月开始有规律, M > n > o 是三个规律相同的变差数列,但是按照 M > n > o 的顺序相差一个月的节奏,其规律都是 1(四月),2(五月),3(六月),4(七月),6(八月),9(九月),13(十月),19(十一月) …
1(四月)+ 3(六月)= 4(七月)
2(五月)+ 4(七月)= 6(八月)
3(六月)+ 6(八月)= 9(九月)
因为兔子三个月才成熟,九月份时,六月出生的兔子也刚好成熟,3(六月)+ 6(八月)= 9(九月)也正好符合这个规律。
案例代码九 数组操作之 不死神兔
package com.itheima;
import java.util.Arrays;
import org.junit.Test;
public class day04 {
@Test
/**
* 需求:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,
* 假如兔子都不死,问第二十个月的兔子对数为多少?
* 设m表示小兔=>M表示成年兔可得:
* 本月兔子数量 = 刚出生m + 一月兔n + 二月兔o + 成年兔数量M (其中m=M)
* =>原公式可简化为:
* 本月兔子数量 = 一月兔n + 二月兔o + 成年兔数量M*2
* 规律:
* 第一个月:n(1 ) + o(0 ) + M(0 )*2 = 1
* 第二个月:n(0 ) + o(1 ) + M(0 )*2 = 1
* 第三个月:n(0 ) + o(0 ) + M(1 )*2 = 2
* 第四个月:n(1 ) + o(0 ) + M(1 )*2 = 3
* 第五个月:n(1 ) + o(1 ) + M(1 )*2 = 4
* 第六个月:n(1 ) + o(1 ) + M(2 )*2 = 6
* 第七个月:n(2 ) + o(1 ) + M(3 )*2 = 9
* 第八个月:n(3 ) + o(2 ) + M(4 )*2 = 13
* 第九个月:n(4 ) + o(3 ) + M(6 )*2 = 19
* 第十个月:n(6 ) + o(4 ) + M(9 )*2 = 28
* 第十一个月:n(9 ) + o(6 ) + M(13)*2 = 41
* 第十二个月:n(13) + o(9 ) + M(19)*2 = 60
*
* 第x个月(其中x>1):{
* n=(x-1)月的M值,
* o=(x-1)月的n值,
* M=(x-1)月的M值+(x-1)月的o值
* }
* 第x月兔子数量 sum = o + p + M * 2
*
* 分析:
* A:由于数据符合递归计算形式,所以我们定义数组,通过循环遍历,由上一个元素值得到下一个元素值
* int[][] arr = new int[20][4];
* 二维数组中存储20个月的兔子情况,每个月的情况用4个值表示{n,o,M,sum}
* arr[x][0]=表示第x月,一个月大的兔子有几对
* arr[x][1]=表示第x月,两个月大的兔子有几对
* arr[x][2]=表示第x月,成年兔子有几对
* arr[x][3]=表示第x月,兔子总数是多少
*
* B:给数组中的元素赋值
* arr[0][0] = 1;
* arr[0][1] = 0;
* arr[0][2] = 0;
* arr[0][3] = 1;
*
* C:第二个月开始
* arr[1][0] = arr[0][3] = 0;
* arr[1][1] = arr[0][0] = 1;
* arr[1][2] = arr[0][1] =
* arr[1][3] = arr[0][2] + arr[0][1] + arr[0][2]*2 = 1;
* arr[1]={0,1,0,1}
*
* D:从第n个月开始,根据规律赋值
* arr[n-1][0] = arr[n-2][3]
* arr[n-1][1] = arr[n-2][0]
* arr[n-1][2] = arr[n-2][1]
* arr[n-1][3] = arr[n-2][2] + arr[n-2][1] + arr[n-2][2]*2
* arr[n-1]={
* arr[n-2][3],
* arr[n-2][0],
* arr[n-2][1],
* arr[n-2][2] + arr[n-2][1] + arr[n-2][2]*2
* }
* ...
* D:输出第二十个月的兔子对数,其实就是输出arr[19][3]
*/
public void OperatorDemo11() {
//定义数组
int[][] arr = new int[20][4];
//给定初始值
//n:
arr[0][0] = 1;
//o:
arr[0][1] = 0;
//M
arr[0][2] = 0;
//sum
arr[0][3] = 1;
for (int i = 0; i < arr.length; i++) {
int[] rabiit = arr[i];
System.out.println("------第" + i + "个月");
if (i >= 1) {
//第i个月 一个月大兔子n取值:上个月成年兔数量M
arr[i][0] = arr[i - 1][2];
//第i个月 二个月大兔子o取值:上个月1个月大兔子数量n = arr[i-1][0];
arr[i][1] = arr[i - 1][0];
//第i个月 成年兔子M取值:上个月2个月大兔子数量o + 上个月M取值
arr[i][2] = arr[i - 1][1] + arr[i - 1][2];
//第i个月 兔子数量之和
arr[i][3] = arr[i - 1][0] + arr[i - 1][1] + arr[i - 1][2] * 2;
}
for (int j = 0; j < rabiit.length; j++) {
//遍历数组
System.out.println("arr[" + i + "]" + "arr[" + j + "]:" + arr[i][j]);
}
}
System.out.println("第20个月兔子数量之和为:" + arr[19][3]);
}
}
/*
------第0个月
arr[0]arr[0]:1
arr[0]arr[1]:0
arr[0]arr[2]:0
arr[0]arr[3]:1
------第1个月
arr[1]arr[0]:0
arr[1]arr[1]:1
arr[1]arr[2]:0
arr[1]arr[3]:1
------第2个月
arr[2]arr[0]:0
arr[2]arr[1]:0
arr[2]arr[2]:1
arr[2]arr[3]:1
------第3个月
arr[3]arr[0]:1
arr[3]arr[1]:0
arr[3]arr[2]:1
arr[3]arr[3]:2
------第4个月
arr[4]arr[0]:1
arr[4]arr[1]:1
arr[4]arr[2]:1
arr[4]arr[3]:3
------第5个月
arr[5]arr[0]:1
arr[5]arr[1]:1
arr[5]arr[2]:2
arr[5]arr[3]:4
------第6个月
arr[6]arr[0]:2
arr[6]arr[1]:1
arr[6]arr[2]:3
arr[6]arr[3]:6
------第7个月
arr[7]arr[0]:3
arr[7]arr[1]:2
arr[7]arr[2]:4
arr[7]arr[3]:9
------第8个月
arr[8]arr[0]:4
arr[8]arr[1]:3
arr[8]arr[2]:6
arr[8]arr[3]:13
------第9个月
arr[9]arr[0]:6
arr[9]arr[1]:4
arr[9]arr[2]:9
arr[9]arr[3]:19
------第10个月
arr[10]arr[0]:9
arr[10]arr[1]:6
arr[10]arr[2]:13
arr[10]arr[3]:28
------第11个月
arr[11]arr[0]:13
arr[11]arr[1]:9
arr[11]arr[2]:19
arr[11]arr[3]:41
------第12个月
arr[12]arr[0]:19
arr[12]arr[1]:13
arr[12]arr[2]:28
arr[12]arr[3]:60
------第13个月
arr[13]arr[0]:28
arr[13]arr[1]:19
arr[13]arr[2]:41
arr[13]arr[3]:88
------第14个月
arr[14]arr[0]:41
arr[14]arr[1]:28
arr[14]arr[2]:60
arr[14]arr[3]:129
------第15个月
arr[15]arr[0]:60
arr[15]arr[1]:41
arr[15]arr[2]:88
arr[15]arr[3]:189
------第16个月
arr[16]arr[0]:88
arr[16]arr[1]:60
arr[16]arr[2]:129
arr[16]arr[3]:277
------第17个月
arr[17]arr[0]:129
arr[17]arr[1]:88
arr[17]arr[2]:189
arr[17]arr[3]:406
------第18个月
arr[18]arr[0]:189
arr[18]arr[1]:129
arr[18]arr[2]:277
arr[18]arr[3]:595
------第19个月
arr[19]arr[0]:277
arr[19]arr[1]:189
arr[19]arr[2]:406
arr[19]arr[3]:872
兔子数量之和为:872
*/
21/01/28
M