1 数组
概念:用于存储多个相同类型的数据,与变量仅在存储数量上有区别。
1.声明定义数组
语法如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
// 定义一个int类型的数组
int[] a;
// 将来a数组中可以存储多个int类型的数据
// 定义一个double类型的数组 b
double[] b;
}
}
2.手动为数组分配空间
作用:避免内存空间的浪费,根据实际需求由自己控制数组的容量。
语法如下:
数组名 = new 数据类型[ 长度 ];
长度:是一个int类型的整数,表示数组的容量,长度是多少将在就可以在数组中存储多少个数据。
演示如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
// 定义一个int类型的数组 a
int[] a; // 将来a数组中可以存储多个int类型的数据
// 定义一个double类型的数组 b
double[] b;
// 为a数组分配5块内存空间
a = new int[ 5 ];
// 为b数组分配10块内存空间
b = new double[ 10 ];
}
}
1.1 数组的下标(索引)
- 概念:数组为每块内存空间自动分配的编号,从0开始到数组长度-1结束。如图所示:
1.2 使用下标操作数据
- 语法如下:
// 访问(查看、获取)数组中的数据
数组名[下标]
// 存储数据
数组名[下标] = 值;
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
// 定义一个int类型的数组 a
int[] a; // 将来a数组中可以存储多个int类型的数据
// 定义一个double类型的数组 b
// double[] b;
// 为a数组分配5块内存空间
a = new int[5];
// 为b数组分配10块内存空间
// b = new double[ 10 ];
a[0] = 100; // 将10保存到a数组中的第1块内存空间
a[1] = 80; // 将500保存到a数组中的第2块内存空间
a[2] = 70; // 将1000保存到a数组中的第3块内存空间
a[3] = 60;
a[4] = 40;
// 获取a数组中第1块内存空间里的数据
int i = a[0]; // 获取数据
System.out.println(i);
// 获取a数组中第2块内存空间里的数据
System.out.println(a[1]);
}
}
如图所示:
- 注意:如果使用非法的下标则出现。
java.lang.ArrayIndexOutOfBoundsException : 非法的下标
数组下标越界异常。
1.3 数组的长度
- 数组提供的一个属性,用于获取数组的长度。
语法:
数组名.length // 可以获取数组的长度。
package com.txw.test;
public class Test {
public static void main(String[] args) {
int[] a;
a = new int[5];
double[] b;
b = new double[15];
// 打印a数组的长度
System.out.println( a.length );
// 打印b数组的长度
System.out.println( b.length );
}
}
- 数组有可能不是我们创建的,通过length可以得知数组的容量。
1.4 数组的名词
- 元素:数组中所存储的数据。
- 获取元素/访问元素:获取数组中的数据。
- 添加元素/移除元素:向数组中添加数据或移除数据。
1.5 遍历数组
- 作用:访问数组中的每个元素。
编程套路:
for(int i = 0; i< 数组名.length; i++){
数组名[i]; //获取元素
}
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
int[] a;
a = new int[ 6 ];
a[0] = 10;
a[1] = 500;
a[2] = 1000;
a[3] = 5;
a[4] = 25;
a[5] = 250;
// 遍历数组
for(int i=0; i<a.length; i++){
System.out.println( a[i] ); // 直接使用
int n = a[i]; // 先提取,再使用
System.out.println( n );
}
}
}
1.6 数组的应用
- 数组作为一种数据类型也可以应用到方法中,作为参数可以接收多个相同类型的数据,作为返回值就可以返回多个相同类型的数据。
演示:定义一个函数接收一个班级所有学生的年龄,打印班级学生的平均年龄。
package com.txw.test;
public class Test {
public static void main(String[] args) {
int [] age = {88,77,66,55,44};
avgAge(age);
}
// 参数类型:数组类型,将来可以接收一个数组类型的数据
public static void avgAge(int[] ages){
// 打印班级学生的平均年龄
int sum = 0; // 记录所有学生年龄的和
// 1.将所有学生年龄相加求和
// 遍历数组
for(int i=0; i< ages.length; i++){
sum += ages[i];
}
// 2.使用结果/人数
System.out.println("平均年龄为:"+ sum / ages.length);
}
}
演示:定义一个函数接收一个整数n,返回n的所有因子。
package com.txw.test;
import java.util.Arrays;
public class Test {
public static void main(String[]args){
int n = 20;
// 1 2 4 5 10 20
int[] result = fac( n );
// java.util.Arrays.toString( result );
System.out.println( Arrays.toString(result) );
}
// 定义一个函数接收一个整数n,返回n的所有因子
public static int[] fac(int n){
int count = 0; // 统计n的因子个数
// 打印n的所有因子
for(int i = 1; i <= n ; i ++){
if(n % i == 0){
count++; // 因子数量+1
}
}
// 用于存储所有因子的数组
int[] fs;
// 数组长度与因子个数一致,没有浪费任何空间
fs = new int[count];
int index = 0; // 自定义下标
// 查找n的所有因子
for(int i = 1; i <= n; i ++){
if(n%i == 0){
// 将因子i存储到数组中
fs[index] = i;
index++; // 下标+1
}
}
// 返回n的所有因子
return fs;
}
}
1.7 数组其他声明定义方式
- 声明定义同时分配空间。
语法如下:
数据类型[] 数组名 = new 数据类型[ 长度 ];
- 演示:
int[] as = new int[10];
- 显式初始化(创建数组时添加元素)。
语法如下:
数据类型[] 数组名;
数组名 = new 数据类型[]{元素1,元素2,元素3.....}
- 演示:
int[] as;
as = new int[]{100, 200, 500, 1000};
- 显式初始化(简写形式,必须保证声明与初始化在同一行语句中)。
语法如下:
数据类型[] 数组名 = {元素1,元素2,元素3....};
- 演示:
int[] as = {100,200,500,1000};
1.8 数组的特性
- 数组元素的默认值
数组在创建时JVM为数组分配内存空间并为每块空间赋予默认值。
演示:
package com.txw.test;
public class Test {
public static void main(String[]args){
// 创建一个int[]类型数组
int[] a = new int[5];
System.out.println( a[3] ); // 0
// 创建一个double[]类型的数组
double[] d = new double[5];
System.out.println( d[2] ); // 0.0
}
}
默认值对照表
数组类型 | 默认值 |
整数类型(byte、shot、int、long) | 0 |
小数类型(float、double) | 0.0 |
字符类型(char) | ‘\u0000’ |
引用类型(String) | null(空) |
引用类型
引用:使用计算机或外部提供的内容到程序中。
特点:
1. 该类型的变量中存储的不是真正的数据,而是内存空间的地址,用以向JVM表明数据的存储位置。
2. 基本数据类型传递数值,引用数据类型传地址。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[]args){
// 基本数据类型
int b = 100;
int c = b; // 将b变量中存储的数据赋值给 c 传递值
b ++;
// 打印变量b中所存储的数据
System.out.println( "b:"+ b +" c:" + c); // 100 101
// 引用数据类型
int[] is = new int[5];
int[] bs = is; // 将is变量中存储的数据赋值给bs 传递地址
//is = null; // 空 啥也没有
is[0] = 100;
// 打印变量is中所存储的数据
System.out.println( "is: "+ is[0] +" bs: "+ bs[0]); // 100 100 因为bs与is共享同一个数组
}
}
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[]args){
// 基本数据类型
int b = 100;
b = changeValue( b ); // 调用一个函数将变量b赋值为b的两倍
System.out.println( b );
// 引用数据类型
int[] is = new int[5]; // 调用一个函数将变量is[0]赋值为100
changeArray( is );
System.out.println( is[0] );
}
public static int changeValue(int b){
return b*2;
}
public static void changeArray(int[] is ){
is[0] = 100;
}
}
数组的长度不可变性与扩容
数组在创建时需要指定长度,长度一旦确定将无法更改,无法再原有基础上进行扩容,因为数组的空间必须保证连续,后续的空间也许被程序中的其他变量所占用,所以数组无法改变原有长度。
数组的扩容:
1. 准备一个更大的数组。
2. 将原数组中的元素拷贝到新数组中。
3. 新数组引用为原数组引用赋值(替代),原数组已没有价值。
扩容方式:
1.手动扩容
演示的代码如下:
package com.txw.test;
import java.util.Arrays;
public class Test {
public static void main(String[]args){
int[] a = new int[3];
a[0] = 10;
a[1] = 200;
a[2] = 1000;
// 为数组扩容
// 1.准备一个更大的数组
int[] b = new int[ a.length*2]; // 6
// 2.将原数组中的元素拷贝到新数组中
for(int i=0; i<a.length; i++){
// 元素复制
b[i] = a[i];
}
System.out.println("扩容前:"+ Arrays.toString(a) );
// 3.新数组引用为原数组引用赋值(替代),原数组已没有价值
a = b;
a[3] = 10000;
// 打印a数组
System.out.println("扩容后:"+ Arrays.toString(a) );
}
}
2.使用System.arraycopy辅助完成元素复制的工作。
语法如下:
System.arraycopy(原数组引用, 拷贝的起始下标,新数组引用,粘贴的起始下标,拷贝几个元素);
演示:
// 将元素组下标为0的元素拷贝到新数组下标为0的位置,向后拷贝5个元素
System.arraycopy(a,0,b,0,5);
演示的代码如下:
package com.txw.test;
import java.util.Arrays;
public class Test {
public static void main(String[]args){
int[] a = new int[3];
a[0] = 10;
a[1] = 200;
a[2] = 1000;
// 为数组扩容
// 1.准备一个更大的数组
int[] b = new int[ a.length*2]; // 6
// 2.将原数组中的元素拷贝到新数组中
System.arraycopy(a,0,b,0,a.length);
System.out.println("扩容前:"+ Arrays.toString(a) );
// 3.新数组引用为原数组引用赋值(替代),原数组已没有价值
a = b;
a[3] = 10000;
// 打印a数组
System.out.println("扩容后:"+ Arrays.toString(a) );
}
}
3。使用java.util.Arrays.copyOf扩容
语法如下:
原数组引用 = java.util.Arrays.copyOf(原数组引用,新数组长度);
// Arrays.copyOf自动创建指定长度的新数组,将原数组中的内容拷贝到新数组,新数组作为返回值返回,注意接收返回值替换原数组
package com.txw.test;
import java.util.Arrays;
public class Test {
public static void main(String[]args){
int[] a = new int[3];
a[0] = 10;
a[1] = 200;
a[2] = 1000;
// 为数组扩容
// int[] b = Arrays.copyOf(a,a.length*2);
// a = b;
a = Arrays.copyOf(a,a.length*2);
a[3] = 10000;
// 打印a数组
System.out.println("扩容后:"+ Arrays.toString(a) );
}
}
1.9 可变长参数
- 作用:JDK5提供的一种形参形式,在一定程度上可以替换数组类型参数。
- 语法:在参数表中使用 数据类型… 参数名 定义参数。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String... args){
int[] as = {10,30,50,1000};
// int[] as = {10,20};
// printSum2(10,20);
// printSum( as ); // 传入数组类型的数据
// printSum(10,20,30); // 自动将数据打包到数组中
printSum(10,2000,20,10,2000,230);
// printSum();
}
// 设计一个函数打印 n个整数 的和
// int... a 可变长参数
public static void printSum(int... a){
// 求和
System.out.println( a.length );
for(int i=0; i<a.length; i++){
System.out.println( a[i] );
}
}
}
注意事项:
1. 一个函数只能有一个可变长参数。
2. 可变长参数必须作为参数表中的最后一个参数。
1.10 数组的排序
- 元素反转。如图所示:
演示的代码如下:
ipackage com.txw.test;
import java.util.Arrays;
public class Test {
public static void main(String[]args){
int[] bs = {100,80,70,60,40,25,16,19};
// bs[0] bs[1] bs[2] bs[3] bs[4] bs[5] bs[6] bs[7]
// 100 80 70 60 40 25 16 19
// 交换位置
// 交换次数:4
// i bs[n-i-1]
// bs[0] vs bs[7] 19 80 70 60 40 25 16 100
// bs[1] vs bs[6] 19 16 70 60 40 25 80 100
// bs[2] vs bs[5] 19 16 25 60 40 70 80 100
// bs[3] vs bs[4] 19 16 25 40 60 70 80 100
// 交换次数
// 数组长度/2
int n = bs.length;
for(int i=0; i<n/2; i++){
// i n-i-1
// as[indexa] as[indexb]
// as[1] as[n-2]
// as[i] vs as[n-i-1];
int temp = bs[i]; // 备份as[i]中的数据
bs[i] = bs[n-i-1]; // 覆盖as[i]中的数据
bs[n-i-1] = temp;
}
System.out.println( Arrays.toString( bs ) );
}
}
冒泡排序
排序规则。如图所示:
演示的代码如下:
package com.txw.test;
import java.util.Arrays;
public class Test {
public static void main(String[]args){
int[] a = {9,8,6,1,4};
for(int j=1; j<a.length; j++){ // 控制比较轮数
for(int i=0; i<a.length-j; i++){ // 控制元素与元素间的比较次数
if(a[i]>a[i+1]){
// 交换位置
int temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
}
}
System.out.println( Arrays.toString( a ) );
}
}
}
- JDK提供的快速排序
java.util.Arrays.sort()
语法如下:
java.util.Array.sort( 数组引用 ); // 自动升序排列
2 习题
- 关于数组的定义,以下正确的是(D) 。
A. int[] a=new int[3]{1,2,3};
B. String s={“a”,“b”,“c”};
C. B. char[] c={“a”,“b”,“c”};
D. int[] a=new int[3];
原因:A选项不应该定义长度。
B选项定义的不是数组,定义数组需要[]。
C选项char类型数组的值应该还是‘’单引号。 - 仔细阅读以下程序代码,对结果描述正确的是©。
package com.txw.test;
public class Test {
public static void main(String[]args) {
int[] a = {2, 4, 6};
for (int i = 0; i <= a.length; i ++) {
System.out.println(a[i] + "\t");
}
}
}
A. 编译报错。
B. 运行结果为:2 4 6。
C. 编译成功,运行报错。
D. 运行结果为:2 4 6 0。
原因:C错误因为循环中i的取值达到了数组的长度,数组最大长度应该是数组长度-1,所以代码会编译成功,运行报错 (ArrayIndexOutOfBoundsException)。
3. 下面对数组 int[] a={1,7,8,9}; 的描述不正确的是(D) 。
A. 数组的下标是从0开始。
B. 数组的内存空间是连续的。
C. 可以将 char 类型的数据存储在a数组中。
D. 数组a中的最大下标是4。
原因:D错误最大下标应该是3。
4. 仔细阅读以下程序,对结果分析正确的是©。
package com.txw.test;
public class Test {
public static void main(String[]args) {
String[] str ={"H","E","L","L","O"};
String r = "";
for (int i = 0; i < str.length; i +2) {
r += str[i];
}
System.out.println(r);
}
}
A. 编译报错。
B. 运行报错 :下标越界。
C… 运行结果为:HLO。
D. 运行结果为:HELLO。
因为循环每次i变量是自增2
5. 编程:定义一个函数,计算一个数组的平均值;在 main 函数中调用并打印输出结果。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[]args) {
// 调用并且打印
System.out.println(aver(new int[] { 10, 15, 20, 25 }));
}
// /定义一个函数求平均值
public static double aver(int[] n){
//总和变量
int sum = 0;
// 得到数组中所有的值相加到sum中
for (int i = 0; i < n.length; i++) {
sum += n[i];
}
// 返回平均值
return (double) sum / n.length;
}
}
- 编程:定义一个 长度为 5 的数组,用于存储学生的成绩,成绩从键盘输入存储到数组中;
要求:
(1) 将所有的成绩倒叙打印输出。
(2) 计算学生的平均成绩。
(3) 键盘输入一个成绩 s,打印出成绩>s 的结果。
演示的代码如下:
package com.txw.test;
import java.util.Scanner;
public class Test {
public static void main(String[]args) {
// 定义长度为5的数组,存储学生成绩
double[] scores = new double[5];
Scanner sc = new Scanner(System.in);
for(int i = 0; i < scores.length; i ++){
// 循环5次,每次键盘录入一个成绩存放在数组中
System.out.println("请输入学生成绩: ");
int score = sc.nextInt();
scores[i] = score;
}
int sum = 0; // 总和
// 倒叙遍历
for(int i = scores.length - 1; i >= 0; i --){
sum += scores[i];
System.out.println(scores[i]);
}
System.out.println("平均成绩为: " + sum / scores.length);
// 键盘录入一个成绩,打印大于这个成绩的数值
System.out.println("请输入一个成绩,会显示数组中大于它的所有值: ");
int score = sc.nextInt();
// 循环得到每一个成绩,判断是否大于用户录入成绩,大于就输出
for(int i = 0; i< scores.length; i ++){
if(scores[i] > score){
System.out.println(scores[i]);
}
}
}
}
- 编程:定义一个整数类型的数组并存储多个数据,获取数组中的最大值和最小值。(不能使用排序)。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[]args) {
int[] a = {1,3,7,5,3,-1};
minMax(a);
}
public static void minMax(int[] a){
if (a == null || a.length == 0)
return;
// 用变量min来统计数组中的最小值
// 用变量max来统计数组中的最大值
// 先让min和max都等于a[0]
// 然后扫描数组中剩下的元素
// 如果某个元素比max更大,则把该元素的值赋值给max
// 如果某个元素比min更小,则把该元素的值赋值给min
// 这样,当扫描完成时
// min中保存的就是最小的元素,max中保存的是最大的元素
int min = a[0], max = a[0];
for(int i = 1; i < a.length; i ++){
if (min > a[i]){
min = a[i];
continue;
}
if (max < a[i]){
max = a[i];
continue;
}
}
System.out.println(min);
System.out.println(max);
}
}
- 编程:自定义一个整数数组 a,读入一个整数 n,如果 n 在数组中存在,则输出 n 的下标;如果不存 在,则输出”此整数在数组中不存在”。
演示的代码如下:
package com.txw.test;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
// 自定义数组a
int[] a = {1, 3, 5, 7, 9};
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个值数组中存在会展示对应下标,数组中不存在会展示-1: ");
int n = sc.nextInt();
// 循环遍历数组,得到每一个元素,判断是否和键盘录入的数值相等,如果相等输出该元素结束主函数
for (int i = 0; i < a.length; i++) {
if (n == a[i]) {
System.out.println(i);
return;
}
}
// 当程序执行到这里说明for循环中if判断一直为false,数组中没有相等的元素,打印-1
System.out.println(-1);
}
}
- 编程:给定一个数组,把这个数组中所有元素顺序进行颠倒,并打印输出。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
int[] a = { 3, 1, 2, 5, 7 };
printArray(a);
reverse(a);
printArray(a);
}
// 让数组中所有元素反转
public static void reverse(int[] a) {
// i变化范围为数组长度的一半
for (int i = 0; i < a.length / 2; i++) {
// 交换a[i]和a[a.length - i - 1],第一个和最后一个交换,第二个和倒数第二个交换
int t = a[i]; a[i] = a[a.length - 1 - i];
a[a.length - 1 - i] = t;
}
}
// 完成遍历int类型数组
public static void printArray(int[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + "\t");
}
System.out.println();
}
}
- 编程:定义一个 char 类型的数组,并存储多个数据; 统计数组中小写字母的个数。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
char[] chs = {'A','a','b','C','1','2'};
// 统计小写字母的个数
int count = 0;
// 遍历数组,得到每一个元素
for(int i = 0; i < chs.length; i ++){
// 判断当前元素是否在a~z之间
if(chs[i] >= 'a' && chs[i] <= 'z'){
// 在a~z之间统计变量+1
count++;
}
}
System.out.println("小写字母的个数: "+count);
}
}
- 编程:定义一个整数类型的数组,分别用冒泡排序法和选择排序法,对数组进行从小到大排序。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
char[] chs = {'A','a','b','C','1','2'};
int[] a = { 5,4,3,2,1 };
printArray(a);
// bubbleSort(a);
selectSort(a);
printArray(a);
}
// 冒泡
public static void bubbleSort(int[] a) {
for (int i = 0; i < a.length-1; i ++) {
for (int j = 0; j < a.length - 1 - i; j ++) {
if (a[j] > a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
// 选择
public static void selectSort(int[] a) {
for (int i = 0; i < a.length - 1; i ++) {
for (int j = i + 1; j < a.length; j ++) {
if (a[i] > a[j]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
//遍历数组
public static void printArray(int[] a) {
for (int i = 0; i < a.length; i ++) {
System.out.print(a[i] + "\t");
}
System.out.println();
}
}
- 编程:5 位评委对参赛选手进行打分,将所有的打分结果存储在对应类型的数组中,将所有评分结果 去除一个最低分,去除一个最高分,然后获取的平均分数为选手的最终得分。设计程序,用键盘输入 5 个评委的评分,并打印输出选手的最终得分。
演示的代码如下:
package com.txw.test;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
// 定义长度为5的数组用来存储评分成绩
int[] a = new int[5];
Scanner sc = new Scanner(System.in);
for (int i = 0; i < 5; i++) {
// 循环录入5次评分成绩,存储到数组中
System.out.println("请输入打分成绩: ");
int score = sc.nextInt();
a[i] = score;
}
// 排序
selectSort(a);
// 定义一个统计变量
int sum = 0;
// 遍历数组从下标1开始,最大下标取到数组长度-2,将此之间的元素相加到sum中。
// 因为数组是排序好的,最小值和最大值分别在数组第一个空间和最后一个空间中,没有加入到sum中
for(int i = 1; i< a.length - 1; i ++){
sum += a[i];
}
// 平均值
System.out.println("平均分是: "+ sum / (a.length-2) );
}
// 选择排序
public static void selectSort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = i + 1; j < a.length; j++) {
if (a[i] > a[j]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
}
总结如图所示: