-
数组
学习笔记——Java基础
数组
解决 : 将数据进行存储 ----》引入∶数组
数组的作用:
数组用来存储数据的,在程序设计中,为了处理方便,数组用来将相同类型的若干数据组织起来。这个若干数据的集合我们称之为数组。
public class Exam5 {
public static void main(String[] args) {
int[] score = new int[5];
int sum = 0;
Scanner sc = new Scanner(System.in);
System.out.print("请输入五位学员的成绩:");
for (int i = 0; i < 5; i++) {
score[i] = sc.nextInt();
sum = sum + score[i];
}
System.out.println(score[4]);
// 这里可以读取到数组存储的数据,不会再循环后找不到
System.out.println("平均分是:"+(double)sum/score.length);
}
}
数组声明:
int [] arr ; int arr[].
数组只声明,不赋值相当于没有定义,不存在内存中;
比如:int[] arr = null; // 此处数组赋值为空,存在。
正常定义数组是 栈中的空间指向堆中的空间,如果定义为null的话,相当于在堆中没有开辟空间,在栈中存的是null。
栈:存放局部变量,形参
堆:new出来的东西
数值创建:
arr = new int[4]; // 给数组开辟一个长度为4的空间。
编译期声明和创建会被合为一句话 : int [ ] arr = new int[4] ;
数组的内存分析:
int [ ] arr = new int[4] ;
堆中存放——>new出来的东西
等号右边的先执行,先在堆中开辟一个空间
arr地址 (16进制) 指向数组下标为 0 的数据存放的地址,然后通过下标取值,int中一个数据占用4个字节,所以其他元素的地址是第一个元素地址加上4乘上下标
数组有默认的初始化值,要看是什么类型的数组:
基本数据类型的数组:
byte[]: 0; short[]:0; int[]:0; long[]:0; float[]:0.0; double[]:0.0
char[] : '\u0000'; (\:转义符;u:unicode码) boolean[] : false
引用数据类型的数组: null(string,objecct...)
数组特点:
1.长度是确定的。数组一旦被创建,它的大小就是不可以改变的;
2.其元素的类型必须是相同类型,不允许出现混合类型;
3.数组类型可以是任何数据类型,包括基本类型和引用类型;
4.数组有索引的:索引从0开始,到数组.length-1结束;
5.数组变量相当于引用类型,数组也是对象;
6.按照位置查询的时候,效率非常高。
数组变量属于引用类型,数组也是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中存储的。
数组的遍历:
1.常用for循环:
for(int i=0 ; i<=9 ;i++){
System.out.println(”第"+(i+l)+"个学生的成绩为:"+scores[i]);
}
2.增强for循环:
(对scores数组进行遍历,遍历出来每个元素都用int类型的num接收)
for (int num: scores){
system.out.println(num);
}
增强for循环:
优点:代码简单
缺点:单纯的增强 for循环不能涉及跟索引相关的操作
数组的初始化:
静态初始化:
除了用new关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值。
int[] arr = {12,23,451};
int[] arr = new int[]{12,23,45};
注意:
1.new int[3]{12,23,457}; -----> 错误
2.int[arr ]; arr = {12,23,45]; --->错误(编译不能识别是一个数组)
动态初始化:
数组定义与为数组元素分配空间并赋值的操作分开进行。
int[] arr ;
arr = new int[3];
arr[0] = 12;
arr[1] = 23;
arr[2] = 45;
默认初始化:
int[] arr = new int[3]
此时数组各个元素均为默认值。
数组的应用:
1. 求数组最大值:
public class Exam7 {
public static void main(String[] args) {
int[] arr = {25, 14, 23, 89, 65};
System.out.println(getMaxNum(arr));
}
//定义一个获取数组中最大值的方法,只需要传入形参arr
public static int getMaxNum(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
}
内存分析:
步骤:
1、程序两个方法,先走main方法,则在栈中为main方法开辟一个栈帧;
2、main中有一个数组,则在堆中为数组开辟一个空间,存放数组元素,各个元素对应自己的地址以及index;
3、然后在main方法开辟的栈帧中有一个局部变量arr,arr的地址指向堆中arr[0]的地址;
4、开始调用getMaxNum方法,同时将arr这个实参传给getMaxNum方法;
java方法中的一切都是值传递,所以将实参arr的地址传给getMaxNum方法
5、在栈中为getMaxNum方法开辟一个栈帧,首先入栈的是arr,所以将main中实参arr的地址传给getMaxNum栈帧中的arr,所以getMaxNum中的arr也可以指向堆中的数组了;
6、给max赋值为arr[0],然后对数组逐步循环判断,循环结束后,return max返回到方法调用处,即输出max,与此同时为getMaxNum开辟的栈帧全部消失,但是堆中的数据不会消失。
方法的实参传递给形参的时候一定要注意:
一切都是值传递:
如果是基本数据类型,那么传递的就是字面值;
如果是引用数据类型,那么传递的就是地址值。
2. 查询问题:
查询指定位置的元素:
查询指定元素的位置:
定义一个方法,查询指定元素:
用for循环以及if判断即可,此处略。
3. 添加元素:
逻辑:
添加元素,需要从后面开始移动元素
import java.util.Arrays;
import java.util.Scanner;
public class Exam8 {
public static void main(String[] args) {
int[] arr = {25, 14, 23, 89, 65, 38};
System.out.print("数组增加前:");
for (int i = 0; i < arr.length; i++) {
if (i < arr.length - 1) {
System.out.print(arr[i] + ",");
} else {
System.out.print(arr[i]);
}
}
//System.out.print(Arrays.toString(arr));
//使用Arrays中的toString方法可以将数组转变为:[25, 14, 23, 89, 65, 38]
Scanner sc = new Scanner(System.in);
System.out.print("\n请输入要插入哪个元素位置之后:");
int j = sc.nextInt();
System.out.print("请输入要插入的数:");
int ele = sc.nextInt();
insertEle(arr, j, ele);
System.out.print("数组增加后:");
for (int i = 0; i < arr.length; i++) {
if (i < arr.length - 1) {
System.out.print(arr[i] + ",");
} else {
System.out.print(arr[i]);
}
}
}
public static void insertEle(int[] arr, int j, int ele){
for (int i = arr.length - 1; i > j; i--) {
arr[i] = arr[i - 1];
}
arr[j] = ele;
}
}
4. 删除操作:
逻辑:
删除一个元素后,删除位置之后的元素往前移动位置,最后一个位置为数组类型的默认值。
import java.util.Arrays;
import java.util.Scanner;
public class Exam9 {
public static void main(String[] args) {
int[] arr = {25, 14, 23, 89, 65, 38};
System.out.print("数组删除前:");
System.out.print(Arrays.toString(arr));
Scanner sc = new Scanner(System.in);
System.out.print("\n请输入要删除元素的位置:");
int j = sc.nextInt();
delEle(arr, j);
System.out.print("数组删除后:");
System.out.print(Arrays.toString(arr));
}
public static void delEle(int[] arr, int j) {
for (int i = j; i <= arr.length-2;i++){
arr[i] = arr[i+1];
}
arr[arr.length-1]= 0;
}
}
main方法讲解
[1] main方法:程序的入口,在同一个类中,如果有多个方法,那么虚拟机就会识别main方法,从这个方法作为程
序的入口
[2] main方法格式严格要求:
public static void main(String[] args){}
public static --->修饰符,暂时用这个-->面向对象一章void --->代表方法没有返回值对应的类型void
main --->见名知意名字
String[] args ---> 形参 ---》不确定因索
[3] 问题:程序中是否可以有其他的方法也叫main方法?
可以,构成了方法的重载。
可变参数
1、概念:作用提供了一个方法,参数的个数是可变的,解决了部分的方法重载问题。
int...num ; double...num ; boolean...num ;
2、方法内对可变参数的处理和数组一样;
3、可变参数 与 单独参数一起时,可变参数需要放在单独的参数前面才能正常编译运行;
4、不建议使用。
Arrays类
方便对于数组的操作
1、toString :
对数组进行遍历查看的,返回的是一个字符串,这个字符串比较好看。
System.out.println (Arrays.tostring (arr));
2、binarySearch :
二分法查找 : 找出指定数组中的指定元素对应的索引
这个方法的使用前提 : 一定要查看的是一个有序的数组
sort : 排序 --> 升序
Arrays.sort(arr) ;
system.out.println(Arrays.tostring(arr)) ;
system.out.println(Arrays.binarySearch(arr,4));
3、 copyof :
完成数组的复制
int[] arr2= {1,3,7,2,4,8};
int[] newArr = Arrays.copyof(arr2,4) ;
//System.arraycopy(arr2,0,newArr,0,arr2.length);
//第一个0代表从原数组那个位置开始,第二个0代表从新数组那个位置开始,arr2.length代表长度
system.out.println(Arrays.toString(newArr)) ;
//结果为[1,3,7,2]
4、copyOfRange :
区间复制
int[]arr2= {1,3,7,2,4,8};
int[] newArr2 = Arrays.copyOfRange(arr2,1,4);
// [1,4)-->1,2,3 位置
system.out.println(Arrays.tostring(newArr2)) ;
//结果为[3,7,2]
5、equals :
比较两个数组的值是否一样
int[] arr3 = { 1,3,7,2,4,8 );
int[] arr4 = { 1,3,7,2,4,8 };
system.out.println(Arrays.equals(arr3,arr4));
// true
System.out.println(arr3==arr4);
//false ==比较左右两侧的值是否相等,比较的是左右的地址值,返回值是false
6、fill :
数组的填充
int[] arr5 = {1,3,7,2,4,8};
Arrays.fail(arr5,10);
System.out.println(arr5);
//将10填进arr5里面的每一个位置
//区间的填充可以用该方法的重载fill(int a,int fromIndex,int toIndex,int value)
数组的复制
System.arraycopy(src,srcPos ,dest ,destPos ,length )
src-源数组。
srcPos -源数组中的起始位置。
dest -目标数组。
destPos -目标数据中的起始位置。
length -要复制的数组元素的数量。
import java.util.Arrays;
public class TestArray{
public static void main (string [] args){
//给一个源数组:
int[] srcArr= {11,22,33,44,55, 66,77,88};
//给一个目标数组:
int[] destArr = new int[ 10];
//复制:
system. arraycopy (srcArr,1,destArr,3,3);
//遍历查看目标数组:
system. out.println (Arrays.toString (destArr));
}
//结果:[0,0,0,22,33,44,0,0,0,0]
二维数组
数组里面放数组
栈中指向第一个堆中的数据,该数据是下一个数组的地址,同时栈也可以指向第二个数组的地址。
二维数组的遍历:
//方式1:外层普通for循环+内层普通for循环:
for(int i= 0;i < arr. length; i++){
for(int j = 0;j<arr[i].length;j++){
system.out.print(arr[i][j]+"\t");
}
system.out.println();
}
//方式2:外层普通for循环+内层增强for循环:
for (int i=0;i<arr.length;i++){
for (int num : arr[i]){
system.out.print(num+"\t") ;
}
system.out.println();
}
//方式3:外层增强for循环+内层增强for循环:
for(int [] a :arr){
for (int num:a){
system.out.print(num+"\t") ;
}
system.out.println() ;
}
//方式4:外层增强for循环+内层普通for循环:
for(int [] a : arr){
for (int i=0 ;i<a.length;i++){
system.out.print (a[i]+"lt");
}
system.out.println();
)
二维数组的初始化
1、静态初始化
除了用new关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值。
eg:
int[][] arr = {{1,23},{4,5,6},{4,5,6,7,8,9,9}};
int[][] arr =new int[][]{{1,2},{4,5,6},{4,5,6,7,8,9,9}};
2、动态初始化
3、默认初始化
教组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
出处:https://www.cnblogs.com/l-926/p/15156892.html