1 数组概述
数组,是一组数据的集合,数组中的每个数据被称为元素。
下面展示一些 内联代码片
。
// 如果有五个数据1 2 3 4 5,需要去接收、保存、操作这些数据,那么需要五个个变量:
int a1 = 1;
int a2 = 2;
int a3 = 3;
int a4 = 4;
int a5 = 5;
除此之外,还可以选择使用一个组数来保存这五个数据:
int[] arr = {1,2,3,4,5};
//这里就是使用了一个数组,来保存这五个数据
在java中,数组也是对象。数组中的元素可以是任意类型(基本类型或引用类类型),但同一个数组里只能存放类型相同的元素。
// main方法的参数,就是一个String类型的数组:
public static void main(String[] args){
//这个参数args的类型是字符串数组
//控制循环输出的次数
int num = 1;
//如果main方法的参数args有接收到参数值的话
if(args.length > 0){
//把接收到的值转换为int类型,并赋值给变量num
num = Integer.parseInt(args[0]);
}
//循环输出hello,默认输出的次数为1,如果用户给main方法传参了,则按照用户的要求的次数进行输 出
for(int i =0;i<num;i++){
System.out.println("hello");
} }
2 数组类型
一般情况下,java中的类(class),是需要提前把代码写好,然后编译成class文件,再加载到内存中,最后在程序中就可以使用到这个类了
而数组和类不同,数组是使用当前已经存在的某一个类型(任意类型都可以),然后再这个类型后面加上一对中括号([]),这时就组成一个了新的类型:数组类型
例如,任意类型 + [] = 相应的数组类型
byte + [] ---> byte[]
short + [] ---> short[]
int + [] ---> int[]
long + [] ---> long[]
float + [] ---> float[]
double+ [] ---> double[]
char + [] ---> char[]
boolean+[] ---> boolean[]
String+ [] ---> String[]
Action+ [] ---> Action[] //Action假设是一个接口
int[] + [] ---> int[][] //一维数组+[] 变为二维数组
数组中可以存放一组数据,要求这一组数据的类型是一样(或者兼容的,兼容就表示可以自动转换)。
例如,int类型数组(int[])中,也是可以存放byte数据的,因为byte可以自动转换为int(兼容)
3 数组变量
先使用一个已有的类型,然后加上中括号,组合成一个数组类型,然后再声明这个数组类型的变量
俩种方式声明一个数组类型的变量:
- int[] a;
- int a[];
推荐使用第一种声明的方式
// 其他一些声明数组变量的示例:
String[] str;
Student[] stus;
Object[] objs;
long[] arr;
int[][] arrOfArr;
//数组类型的变量,也是引用类型变量,简称引用,它是可以指向对象的(数组对象)
4 数组对象
下面展示一些 内联代码片
。
// 使用new关键字,来创建数组对象,中括号里面的数字,就是数组的长度。
int[] a = new int[4];//数组对象a中,最多存放4个int类型的数据
String[] s = new String[2];//数组对象s中,最多存放2个String类型的数据
char[] c = new char[1];//数组对象c中,最多存放1个char类型的数据
//数组对象,在内存中,就是一块连续的内存空间,在这个连续的空间中,可以存放多个类型相同的数据。
5 数组长度
数组对象的长度:
1. 数组长度,是指在一个数组对象中,最多可以存放多少个同一类型的数据
2. 数组长度,必须在创建数组对象的时候就明确指定
3. 数组长度,一旦确定,就无法再改变
4. 数组长度,可以为0,但是不能为负
// 例如,错误的一些情况
//编译报错,因为没指定数组的长度
byte[] b = new byte[];
//编译通过,但是运行报错,因为数组的长度不能为负数
byte[] b = new byte[-1];
//例如,使用length属性,获取数组对象的长度
int[] a = new int[4];
System.out.println(a.length);
6 数组下标
int[] a = new int[4];//数组长度为4,那么其下标就是0~3
a[4] = 359;//这句代码运行时报错,下标超出了最大范围
//可以通过数组下标,给数组某个下标位置上赋值:
int[] a = new int[4];
a[0] = 337;
a[1] = 340;
a[2] = 348;
a[3] = 352;
//可以通过数组下标,获取数组某个下标位置上的值:
int[] a = new int[4];
System.out.println(a[0]):
int num = a[0]+a[1]+a[2]+a[3];
System.out.println(num);
//可以结合循环来进行赋值或者取值:
int[] a = new int[4];
//i从0开始,到a.lenght-1,那么i的取值刚好是数组a的下标可用范围
for(int i=0;i<a.length;i++){
a[i] = 10+i;
}
//获取数组中每个下标的值,并且输出
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
7 默认值
一个数组对象在创建的时候,需要指定数组长度,表示数组中最多存放的元素个数,并且在数组对象创建完成之后,数组中每一个元素位置上,就已经有了相应的默认值,这个默认值和数组的类型有关
8 创建方式
9 数组拷贝
数组对象的长度确定之后便不能修改,但可以通过复制数组的内容变通实现改变数组长度
// 在java.lang.System类中提供一个名为arraycopy的方法可以实现复制数组中元素的功能
//该方法的声明
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
//参数1,需要被复制的目标数组
//参数2,从目标数组的哪一个位置开始复制
//参数3,需要把数据复制到另外一个新的数组中
//参数4,把数据复制到新数组的时候,需要把数据从什么位置开始复制进去
//参数5,复制的目标数组的长度
//例如,写一个方法,接收一个数组对象,把这个数组对象的长度扩大到原来的2倍并返回
public int[] test(int[] a){
int[] b = new int[a.length*2];
System.arraycopy(a, 0, b, 0, a.length);
return b;
}
10 工具类
//注意,数组长度一旦确定,就不能再修改了。
//我们只是创建了一个新的数组,并且把老数组中的数据复制到了新数组中,并且把新数组返回给用户,这个 效果让人感觉上像是老的数组的长度变长了,但其实并没有。
int[] a = {1,3,5,2,6,8};
System.out.println(Arrays.toString(a));
a = Arrays.copyOf(a,10);
System.out.println(Arrays.toString(a));
Arrays.sort(a);
System.out.println(Arrays.toString(a));
int index = Arrays.binarySearch(a,5);
System.out.println(index);
int[] arr1 = {1,2,3};
int[] arr2 = {3,2,1};
Arrays.sort(arr1);
Arrays.sort(arr2);
System.out.println(Arrays.equals(arr1,arr2));
Arrays.fill(a,100);
System.out.println(Arrays.toString(a));
11 案例
例如,实现一个方法,参数是int[],该方法可以计算出数组中所有数据的平均值,并且把结果返回
public double test(int[] arr){
int length = arr.length;
int sum = 0;
for(int i=0;i<length;i++){
sum = sum + arr[i];
}
return sum/length;
}
例如,实现一个方法,参数是int[],该方法可以计算出数组中所有数据的最大值,并且把结果返回。
public int test(int[] arr){
//max变量中的值,表示当前找到的最大值
//假设数组中下标为0的位置是最大值
//这步假设赋值的目的就是为了给局部变量max一个初始值
int max = arr[0];
for(int i=1;i<arr.length;i++){
if(arr[i]>max){
max = arr[i];
}
}
return max;
}
//冒泡排序
public void test(int[] arr){
//获取到数组的长度
int len = arr.length;
//外层循环控制一共比较几轮
for(int i=0;i<len-1;i++){
//内层循环控制每轮比较多少次数,每轮比较的次数是有变化的
for(int j=0;j<(len-i-1);j++){
//比较俩个相邻数据的大小
//如果前一个数据比后一个数据大
if(arr[j]>arr[j+1]){
//交互这个俩个数据的位置
arr[j] = arr[j] ^ arr[j+1];
arr[j+1] = arr[j] ^ arr[j+1];
arr[j] = arr[j] ^ arr[j+1];
}
}
//这个输出,可以看到每一轮比较结束后的结果是怎样的
System.out.println("\t"+Arrays.toString(arr));
}
}
下面展示一些 内联代码片
。
//注意,操作的核心目标:
// 1.每轮找到的最小值应该存放的下标位置是什么
// 2.每轮找到的最小值现在的下标位置是什么
// 3.找到之后,让这俩个位置的值进行交互就可以了
// 4.注意,最后一个数字就不用在比较了(前面都排好了,最后一个一定是最大的)
public void test(int[] arr){
//数组的长度
int len = arr.length;
//min_now_index表示最小值【当前】在什么位置
int min_now_index;
//min_should_index表示最小值【应用】在什么位置
int min_should_index;
//外层循环,控制一共要比较多少轮,同时这个变量i,刚好是每轮我们需要指定的最小值应该存放位 置。
for(int i=0;i<len-1;i++){
//每一轮i的值,刚好就是本轮最小值应该存放的位置。
min_should_index = i;
//假设当前i的位置就是本轮最小值的实际位置
min_now_index = i;
//内层循环,负责每轮找出当前未排序区中的一个最小值的实际位置的下标
for(int j=i+1;j<len;j++){
//哪个数据小,就把这个数据下标赋值给min_now_index
//目的是让了min_now_index变量中始终保持当前未排序区中的最小值的位置
if(arr[j]<arr[min_now_index]){
min_now_index = j;
}
}
//内层循环结束后,就明确了当前未排序区中的最新值的下标,以及这个最小值应该存放在什么位 置
//接下来可以进行交互位置
if(min_now_index != min_should_index){
int temp = arr[min_now_index];
arr[min_now_index] = arr[min_should_index];
arr[min_should_index] = temp;
}
}
}
12 二维数组
如果把普通的数组(一维数组),看作一个小盒子的话,盒子里面可以存放很多数据,那么二维数组就是像一个大点的盒子,里面可以存放很多小盒子(一维数组)
12.1 理解二维数组
//三个一维数组
int[] a1 = {1,2,3};
int[] a2 = {2,3,4};
int[] a3 = {3,4,5};
//二维数组中,存放三个一维数组对象
int[][] arr = {
a1,
a2,
a3
};
//等价于上面的代码
int[][] arr = {
{1,2,3},
{2,3,4},
{3,4,5}
};
12.2 声明和创建
下面展示一些 内联代码片
。
//第一个中括号中的4,代表这个二维数组对象里面,最多可以存放4个一维数组 //第二个中括号中的3,代表这个二维数组中,每个存放的一维数组对象,都可以存放存放3个int数据
int[][] a = new int[4][3];
//这句代码等价于以下代码
int[][] a = new int[4][];
a[0] = new int[3];
a[1] = new int[3];
a[2] = new int[3];
a[3] = new int[3];
//这句代码等价于以下代码
int[][] a = {
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0}
};
可以把这个二维数组,理解为一栋大厦,共有4层楼,每层楼有3间房,每个房间可以存放一个int数据,现在每个房间的默认值都是0
12.3 赋值
12.4 取值
String[][] str = {
{"test1"},
{"hello1","hello2"},
{"world1","world2","world3"}
};
//循环三次,因为str中有三个元素
//只不过这三个元素每一个都是个一维数组
for(int i=0;i<str.length;i++){
//第一个一维数组中有1个元素,元素是String类型的
//第二个一维数组中有2个元素,元素是String类型的
//第三个一维数组中有3个元素,元素是String类型的
//所以内层循环每次打印的次数是不一样的
for(int j=0;j<str[i].length;j++){
System.out.println(str[i][j]);
}
}
12.5 案例
//参数line,表示需要输出的行数
public void test(int line){
int[][] arr = new int[line][];
//根据规律,构造出二维数组并且赋值
for(int i=0;i<arr.length;i++){
arr[i] = new int[i+1];
//循环给二维数组中的每个位置赋值
for(int j=0;j<arr[i].length;j++){
if(j==0 || j==arr[i].length-1){
arr[i][j] = 1;
}
else{
//除了下标中的0和最后一个,其他的元素都具备相同的规律
//这个位置的值=上一层和它相同下标的值+前一个元素的值
arr[i][j] = arr[i-1][j] + arr[i-1][j-1];
}
}
}
//把赋值完成的二维数组按要求进行输出
for(int i=0;i<arr.length;i++){
//控制每行开始输出的空格
for(int j=0;j<(arr.length-i-1);j++){
System.out.print(" ");
}
//控制输出二维数组中的值,记得值和值之间有空格隔开
for(int k=0;k<arr[i].length;k++){
System.out.print(arr[i][k]+" ");
}
}
13 可变参数
JDK1.5或者以上版本中,可以使用可变参数
下面展示一些 内联代码片
。
// 例如,假设有这样一个方法,参数 int[] 类型
public void test(int[] a){
//...
}
//在调用这个方法的时候,【只能】传一个数组对象作为参数
int[] arr = {1,2,3};
t.test(arr);
// 例如,如果使用可变参数的语法,上面的方法就可以变成下面的情况:
public void test(int... a){
}
//在调用这种方法的时候,我们所传的参数情况就可以有多种选择了
int[] arr = {1,2,3};
t.test();
t.test(1);
t.test(1,2,3,4);
t.test(arr);
在test方法中,这个可变参数a,其实就是一个int类型的数组,在方法中可以直接把a当做数组来使用。
如果没有传任何参数,那么这个数组a的长度就是0
如果传1个参数,那么数组a的长度是1,数组里面的数据就是所传的参数。
依次类推,传多个参数的情况也是类似的。
额外的,还可以把一个数组当做参数传进来,因为这个可变参数a,本来就是一个数组。
例如,方法中有一个可变参数同时,还可以有其他普通的参数
public void test(String str,int... a){
}
注意,可变参数和普通参数共存的时候,可边参数必须放到最后一个参数的位置