JavaSE【4】-数组
JavaSE【4】-数组
引导:
目前我们所使用的变量在程序运行的任意的瞬间都只能保存一个数据值,这样对程序来讲是远远不够的,因为我们在某些场景之下,需要进行一个批量数据的存储。
例如: 保存一个班级的学生的信息 、保存所有的学生的成绩信息............
此时,Java语言中就提供了一种叫“数组"的概念。
一、数组的定义
数组:就是一组数,用于保存【固定大小】的【同种类型】数据的一种【简易集合】;
固定大小:要求在数组创建的时候必须要确定其大小;
同种类型:数组中保存的数据的数据类型是同一种类型;
简易集合:批量数据;
提示!
数组是我们学习到当前为止所见到的第一个“复合引用”类型;
二、数组的创建
在Java程序中创建出一个数组对象,可以有如下几种做法:
1、 int[] is = new int[3];
2、 int[] is;
is = new int[3];
以上的这种创建方式,只是给我们创建出了数组对象,并且分配了内存空间,数组中的元素都是int类型的默认值;
3、int[] is = {1,2,3,4};
4、int[] is = new int[]{1,2,3,4,5};
以上的这种创建方式,不仅仅创建了数组的对象,而且我们进行了手动初始化;
//数组的创建
public static void main(String[] args) {
//数据类型[] 变量名称 = new 数据类型[长度];
//数据类型 变量名称[] = new 数据类型[长度];
//数据类型:包含Java中所有的数据类型 int[] , double[] ,boolean[] , String[] ,
//Student[] ......
//表示在计算机的内存中开辟了一个可以保存3个int类型整数的存储空间;
int[] as = new int[3]; // int类型----32位【4个字节(一个字节是8位)】(空间) 4byte -- kb ---- MB ----GB ---T
//new关键字:就是在开辟内存并创建出一个数组的对象;
//as变量名称:as保存的是new出来的真实的对象在计算机内存中所占据的完整地址的首地址;
//第一步:声明一个数组
String[] bs;
//第二步:创建出数组对象,并且分配内存空间
bs = new String[4];
System.out.println(bs);
//声明和创建同时进行,并且进行了手动赋值
char[] cs = {'a','b','c','d'};
//声明和创建同时进行,并且进行了手动赋值
double[] ds = new double[]{1.2,2.3,3.4,4.5};
}
三、数组的内存分布
说明:
1、new int[3] :真实的数组对象是保存在堆内存中的;
2、is:是保存在栈内存中;
3、is 和 真实的数组对象的关联,靠的是is中保存的是真实数组对象在堆区中的完整地址的首地址;
四、数组的地址引用
public static void main(String[] args) {
int[] as1 = {1,2,3,4,5}; // as1 地址: 123x
int[] as2 = {10,20,30,40}; //as2 地址:456x
as2 = as1; //属于值传递,只不过这个值是一个内存地址(数组完整的地址的首地址);
//as2中保存的也是 123x这个地址;
System.out.println(Arrays.toString(as1));
System.out.println(Arrays.toString(as2));
//判断的是内存地址是否一致(判断as1和as2是不是同一个数组对象)
System.out.println(as1==as2); //true
//本质上就是同一个数组对象,取了2个不同的别名;
System.out.println(as1[2]);
System.out.println(as2[2]);
}
五、数组的操作
5.1、针对数组进行赋值操作
// 针对数组进行赋值操作
public static void test1() {
// 创建数组,内部默认的是3个0
int[] is = new int[3];
// 输出的是数组的地址
System.out.println(is);
// 使用懒惰的方式进行数组内容的查看
System.out.println(Arrays.toString(is));
//创建数组的目的是,用于保存我们需要保存的一些数据;
is[0] = 10;
is[1] = 50;
is[2] = 100;
//数组进行赋值操作的过程中,我们都是使用的数组的下标来完成的;
//注意!只要是数组都会存在所谓的下标,下标就是为了按照位置来标识每一个独立的元素,是从0开始的,到长度-1为止;(这种下标的生成是自己自动生成的)
System.out.println(Arrays.toString(is));
//当我们使用下标为3的时候,其实已经超出了数组的合法下标范围
//这时程序就会抛出一个 java.lang.ArrayIndexOutOfBoundsException 数组下标越界异常;
//is[3] = 40; 错误的;
}
提示!
针对数组进行动态赋值操作,依赖的是数组的下标;
5.2、针对数组进行取值操作
//针对数组进行取值的操作
public static void test2(){
char[] cs = {'a','b','c','d'};
//取值---同样依赖的是下标(肯定也是不能超出下标范围的)
char value1 = cs[1];
System.out.println(value1);
char value2 = cs[3];
System.out.println(value2);
}
提示!
取值的时候,也是不能超出数组下标的范围,否则也会抛出异常;
5.3、数组的遍历
遍历:就是将一个集合中的数据按照顺序一个一个的取出;
数组.length; 这是数组对象中的一个属性length,用于获取指定数组的长度(或 元素的个数);
//数组的遍历
public static void test3(){
char[] cs = {'a','b','c','d'};
System.out.println(cs.length);
//第一种方式(标准for循环)
for(int i=0;i<cs.length;i++){
char value = cs[i];
System.out.println(value);
}
System.out.println("************************");
//第二种方式(for增强循环)
for(char c:cs){
System.out.println(c);
}
}
提示!
在上面的方式中,我们使用到了for增强循环,需要注意for标准循环和for增强循环的区别:
能够使用for增强循环处理的情况,同样可以使用for标准循环来实现;
但是for标准循环能够处理的情况,不一定能使用for增强循环来完成;
5.4、数组的复制
所谓的复制,就是定义一个新的数组和原来的数组中的数据是保持一致的,实现数组的复制有如下几种方式:
第一种方式:通过下标一个一个的取值,并在新数组中对应的进行赋值;
//数组的复制-方式1
public static void test1(){
int[] is = {1,2,3,4,5,6};
System.out.println(Arrays.toString(is));
//量身定制一个新的数组
int[] newIs = new int[is.length];
for(int i=0;i<is.length;i++){
//取值并赋值
newIs[i] = is[i];
}
System.out.println(Arrays.toString(newIs));
//附加内容
System.out.println(is==newIs); // false
//说明:is 和 newIs的内存地址是不同的(也就是说is 和 newIs是两个完全不同的数组对象,仅仅只是数组中的元素相同而已);
}
第二种方式:使用数组对象中的克隆的方法来进行实现;
//数组的复制-方式2
public static void test2(){
int[] is = {1,2,3,4,5,6};
System.out.println(Arrays.toString(is));
int[] newIs = is.clone();
System.out.println(Arrays.toString(newIs));
System.out.println(is==newIs); // false
//说明:is 和 newIs的内存地址是不同的(也就是说is 和 newIs是两个完全不同的数组对象,仅仅只是数组中的元素相同而已);
}
引导:
//区分基本类型和复合引用类型的不同之处
public static void test(){
int x = 30;
//备注!针对x这个基本数据类型的变量,只能进行赋值 和 相应的使用,不具备其他功能了;
x = 40;
int[] y = {1,2};
//使用的是y这个对象的属性length;
int len = y.length;
//使用的是y这个对象的方法(功能)
int[] newY = y.clone();
/**
* 总结一下:
* 基本类型仅仅是数据的一种表示,不具备其他任何的数据操作;而复合引用类型除了表数数据之外,
* 还具有操作这个数据的方法和属性;
*/
}
第三种方式:使用System类中arraycopy方法来实现:
System.arraycopy(src, srcPos, dest, destPos, length);
注意参数!
src:指代的是原始的数组;
srcPos:指代的是原始数组中需要复制的开始的位置;
dest:指代的是目标数组;
destPos:指代的是目标数组中保存数据的开始位置;
length:表示复制的元素的个数;
// 数组的复制-方式3
public static void test3(){
int[] is = { 1, 2, 3, 4, 5, 6 };
System.out.println(Arrays.toString(is));
//创建一个目标数组
int[] dest = new int[is.length];
//使用System类中的方法来实现数组的复制
System.arraycopy(is, 0, dest, 0, is.length);
System.out.println(Arrays.toString(dest));
}
第四种方式:使用的是Arrays类中的copyOf方法来实现
Arrays.copyOf(src, newLength);
参数说明:
src:指代的是原始数组;
newLength:指代的是新的数组的长度;
// 数组的复制-方式4
public static void test4(){
int[] is = { 1, 2, 3, 4, 5, 6 };
System.out.println(Arrays.toString(is));
//使用的是Arrays类中的copyOf方法来实现的;
int[] newIs = Arrays.copyOf(is, is.length);
System.out.println(Arrays.toString(newIs));
}
5.5、数组的排序
我们在开发的过程中,避免不了需要针对数组进行相关的排序处理,那么如何针对数组进行排序呢?
我们提供出了如下两种方案:
第一种:使用Arrays类中的方法进行升序的排序处理
//数组的排序---1(使用Arrays类中的sort方法来实现)
public static void test1(){
int[] is = {7,2,6,4,5,3,1};
//使用sort方法按照从小到大的顺序进行排列;
Arrays.sort(is);
System.out.println(Arrays.toString(is));
}
第二种:使用自定义的手动排序法来进行排序处理
//数组的排序---2(使用手动排序法来进行排序【冒泡法】)
public static void test2(){
int[] is = {7,2,6,4,5,3,1};
System.out.println("原始数组:"+Arrays.toString(is));
//进行第一轮的排序处理 i=6
for(int j=1;j<is.length;j++){
for(int i=0;i<is.length-j;i++){
if(is[i]>is[i+1]){
//交换位置
int stemp = is[i];
is[i] = is[i+1];
is[i+1] = stemp;
}
}
}
System.out.println("最终结果:"+Arrays.toString(is));
}
总结:
1、Arrays类中的sort方法实现排序非常的简单,但是不够灵活;
2、使用手动排序法来进行排序代码相对比较复杂,但是比较灵活;
上机任务:
任务1: 通过控制台录入的方式录入5位学员的成绩,并保存在数组中,最终计算出5位学员平均分;
任务2: int[] is = {3,7,2,5,10,6,4}求出数组中的最大值;
任务3: 向数组中合适的位置插入一个元素;
{1,7,3,2,4,5} --- 排序处理 -----{1,2,3,4,5,7}
输入了一个 6 数值;
{1,2,3,4,5,6,7}
//假设法的使用
//任务2: int[] is = {3,7,2,5,10,6,4}求出数组中的最大值;
public static void test1(){
int[] is = {3,70,2,5,10,6,4};
//假设法
int max = is[0];
for(int i=1;i<is.length;i++){
if(is[i]>max){
max = is[i];
}
}
System.out.println(max);
}
//任务3: 向数组中合适的位置插入一个元素;
public static void test2(){
int [] is = {1,7,3,2,4,5,8,9};
//第一步:针对数组进行排序,构建一个标准序列的数组元素排列,才能谈得上所谓的合适的位置;
Arrays.sort(is);
//is = [1, 2, 3, 4, 5, 7,8,9]
System.out.println(Arrays.toString(is));
//用户录入一个6的数据,就应该排列在 5 和 7之间的位置;
//需要构建一个新的长度为is.length+1大小的数组
int[] newIs = new int[is.length+1];
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数:");
int input = sc.nextInt();
//定义一个保存下标位置的变量
int index = 0 ; // 5
//确定出输入数据6的保存位置;
for(int i=0;i<is.length;i++){
if(is[i]>input){
index = i;
break;
}
}
System.out.println(index); // 5,其实就是输入的数据应该保存的位置;
//使用复制的形式来进行实现=========
System.arraycopy(is, 0, newIs, 0, index);
//插入新录入的数据input
newIs[index] = input;
System.arraycopy(is, index, newIs, index+1, is.length-index);
System.out.println(Arrays.toString(newIs));
//完全使用下标进行复制的形式来实现的============
/*for(int i=0;i<index;i++){
newIs[i] = is[i];
}
System.out.println(Arrays.toString(newIs));
newIs[index] = input;
System.out.println(Arrays.toString(newIs));
for(int i=index;i<is.length;i++){
newIs[i+1]=is[i];
}
System.out.println(Arrays.toString(newIs));*/
}
六、Arrays类
6.1、Arrays类简介
在Java API中提供了一个数组操作的辅助类(Arrays类),这个类位于java.utli包下,用于数组操作的补充和扩展。这个类中都是静态的方法,所以我们通过【类名.直接可以调用】。
6.2、Arrays类常用方法
需要掌握的方法如下:
Arrays.toString(is); //懒惰输出方式
Arrays.sort(is); //排序
int index = Arrays.binarySearch(is, 8); //元素查找
int [] newIs = Arrays.copyOf(is, is.length); //数据复制
Arrays.fill(is, 100); //数据填充
Arrays.equals(is1,is2); //数组元素的比较
Arrays.asList("admin","lucy","tom");//将数组转换为List集合(后续到集合章节讲解)
提示!
注意学习一个新的类的时候,需要对照API手册来进行学习;
6.3、附加内容
可变参数的使用:
public static void main(String[] args) {
/*int[] x = {10,20,30,40};
test1(x);*/
//使用可变参数会比较的方便和灵活
test2(10,20);
}
//求出多个数之和
public static void test1(int[] is){
int sum = 0 ;
for(int v : is){
sum+=v;
}
System.out.println(sum);
}
//求出多个数之和
public static void test2(int... is){ // int... 这种写法表示的是可变参数,只能使用在参数列表的末端位置;
int sum = 0 ;
for(int v : is){
sum+=v;
}
System.out.println(sum);
}
提示!
在一个参数列表中,最多只能使用一个可变参数,并且是在末尾的位置;
七、多维数组
在Java语言中,数组可以存在多维的概念,但是我们从使用的角度最多能够使用到二维数组。所谓的二维数组,其实就是【数组的数组】,即(一个二维数组中的每一个元素都是一个一维数组)。
7.1、二维数组的创建
// 第一个[] 表示的是高维: 表示的是这个二维数组有多少个一维数组的元素;
// 第二个[] 表示的是低维: 表示的是每个二维数组的元素(一维数组)的元素的个数;
int[][] is2 = new int[3][5];
//注意!在创建二维数组的时候,可以直接给 【高维进行分配】或者【高低维同时分配】;
//以上的二维数组表达的含义是:
//这个二维数组有3个一维数组的元素;
//而每一个一维数组中有5个元素;
int len1 = is2.length;
System.out.println(len1); // 3
int len2 = is2[0].length;
System.out.println(len2); // 5
7.2、二维数组赋值和遍历
//二维数组的赋值操作
public static void test2(){
int[][] is2 = new int[3][5];
is2[0] =new int[]{1,2,3,4,5};
is2[1] =new int[]{11,22,33,44,55};
is2[2] =new int[]{10,20,30,40,50};
//如何遍历
for(int[] is : is2){
System.out.println(Arrays.toString(is));
}
int[][] aa = new int[3][];
//分配每一个一维数组
aa[0] = new int[]{1,1,1};
aa[1] = new int[]{1,2,3,4};
aa[2] = new int[]{12,12};
for(int[] a : aa){
System.out.println(Arrays.toString(a));
}
}
应用场景分析:
如果想表示一个班级的所有的学生的成绩,我们可以使用“一维数组”;
如果想表示出整个年级的不同班级的学生的成绩,我们可以使用“二维数组”;
我们在程序的开发中,最多会使用到“二维数组”,如果有更多层级的数据表示,我们就会选择使用集合容器了
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决