文章目录
一、数组的基本知识
1.1 引入数组
功能:从键盘输入10个学生的分数,求和,并求平均分,输出。
思路1:定义一个变量sum、avg,分别存储总分、平均分;定义10个变量score1、score2、score3…score10,分别存储一个分数。
缺点:定义的变量太多。
思路2:定义一个变量sum、avg,分别存储总分、平均分;定义1个变量score,依次存储一个分数。借助循环,完成功能。
缺点:不能同时存储10个分数。
思路3:定义一个变量sum、avg,分别存储总分、平均分;定义一个数组,由10个元素组成,每个元素相当于是1个变量,总体构成一个更大的变量。
优点:变量只有一个scoreArr,也可以同时存储10个分数
数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素element,每个元素可以通过一个索引index(下标)来访问它们。数组的基本特点:
1. 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
2. 在内存中分配连续的空间,每个元素占用的空间大小是相同的
3. 同一个数组其元素的类型必须是相同类型,不允许出现混合类型。
4. 数组类型可以是任何数据类型,包括基本类型和引用类型。
5. 数组变量属于引用数据类型
1.2 声明数组
type[] arr_name; //方式一(推荐使用这种方式)
type arr_name[]; //方式二
public class Test1{
public static void main(String[] args){
* 数组 多个性质相同或者相近的数据的集合 array
* java数据类型 基本数据类型 八个
* 引用类型 String array
* */
/*
* 数组的声明和创建
* int[] arr; 推荐
* int ar[];
* 数组中的每个数据叫做元素
* */
int[] arr={5,7,56,85,13,54,95,51};
// 0 1 2 3 4 5 6 7
// 数组的长度属性 数组中能装多少个元素 长度属性是int值 数组的长度一旦创建就不可以改变了
int l =arr.length;
System.out.println(l);
// 数组拥有索引属性 索引 index 就是元素的编号 从0开始,从前向后依次递增
// 根据索引或者数组中的指定的元素
int e=arr[5];
System.out.println(e);
// 数组中的元素是可以修改的
arr[5]=100;
System.out.println(arr[5]);
for (int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
}
}
注意事项
声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关。
声明一个数组的时候并没有数组真正被创建。
构造一个数组,必须指定长度。
1.3 数组的初始化
数组的初始化方式总共有三种:静态初始化、默认初始化、动态初始化。
1 静态初始化
声明数组、分配空间、元素赋值合并在一起实现。
int [] scoreArr = new int[] {10,20,30,70,60,79,45,34,23,100} ;
int[] scoreArr = {10,20,30,70,60,79,45,34,23,100};
int[] scoreArr = new int[10]{10,20,30,70,60,79,45,34,23,100};//该方式是错误的
2 默认初始化
int a2[] = new int[2]; //默认值是0,0
boolean[] b = new boolean[2]; //默认值: false,false
String[] s = new String[2]; //默认值:null,null
3.动态初始化
元素的赋值和声明数组、分配空间分开实现
int [] scoreArr = new int[10];
scoreArr[0] = 56;
scoreArr[1] = 78;
scoreArr[9] = 100;
测试代码
public class Test2 {
public static void main(String[] args) {
// 静态初始化 静态创建 在创建数组的时候支架将元素的值自定义指定
//double[] arr={10.1,4.56,6.12,3.14,5.23,6.0,7.1};//声明和创建必须在同一行
// 0 1 2 3 4 5 6
double[] arr;
arr=new double[]{10.1,4.56,6.12,3.14,5.23,6.0,7.1};// 声明和创建可以分开
//double[] arr =new double[10]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.1};// 错误的
for (int i = 0; i <arr.length ; i++) {
System.out.println(arr[i]);
}
// JVM自动初始化 动态创建 创建数组时,仅仅规定数组的长度(容量) 元素的值交给JVM自动初始化
/*
* byte short int long 0
* char \u0000 ' '
* float double 0.0
* boolean false
* String 引用类型 null 空引用
* */
char[] carr=new char[10];
for (int i = 0; i <carr.length ; i++) {
System.out.println(carr[i]);// \u0000
}
String[] iarr=new String[10];
for (int i = 0; i < iarr.length; i++) {
System.out.println(iarr[i]);
}
}
}
1.4 数组内存分配
1. 声明数组
在方法中声明的基本数据类型的变量,仅仅占用栈内存的空间,引用类型的数据创建时,会占用堆内存,但是声明变量不会在堆内存中产生空间的占用
public static void main(String[] args) {
String s;
int[] arr;
}
2.给数组分配空间
1基本数据类型的变量在方法中创建完毕后,仅仅占用栈内存,引用类型要占用两个空间,堆内存上存放数据,栈内上引用堆内存上的地址
2 数组的元素在内存上是连续的
3 栈内存上存储的是数组首元素的地址
public static void main(String[] args) {
int i=10;
String s="asdf";
int[] arr={5,7,1,6,8};
}
3.给数组元素赋值
public static void main(String[] args) {
int i=10;
String s="asdf";
int[] arr=new int[5];
}
arr[0]=5;
arr[1]=6;
arr[2]=7;
arr[3]=3;
arr[4]=1;
总结:
1.栈内存
- stack memory
- 存放局部变量、数组名,没有默认值
- 每调用一个方法会开辟一个栈帧,方法执行完立刻回收该栈帧,后进先出
2.堆内存
- heap memory
- 存放真正的数组元素,有默认值
- 方法执行完毕后不会立刻释放资源,由垃圾回收器负责回收;程序员不用操心 但时间不确定
3.数组元素的默认值
1.5 数组的遍历
JDK1.5提供了增强的for循环功能,可以简化遍历数组的操作,但是不能进行和索引相关的操作,遍历数组过程中不能修改数组中某元素的值。功能其实没有增加。
for循环遍历数组
public class Test3{
public static void main(String[] args){
int[] arr = {5,4,3,1,9,2,7,8,0,6};
//普通的for循环遍历
for(int i= 0;i<arr.length;i++){
system.out.printIn(arr[i]);
}
}
}
foreach循环遍历数组
public class Test2 {
public static void main(String[] args) {
String[] arr={"asdf","qwer","zxcv","abcd"};
double[] darr={10.1,2.3,5.6,3.8,4.7};
// 1.5 增强型for循环 foreach循环
for(String str:arr){
System.out.println(str);
}
for(double dou:darr){
System.out.println(dou);
}
}
}
foreach循环使用特征
public class Test {
public static void main(String[] args) {
double[] darr={10.1,2.3,5.6,3.8,4.7};
/*
* 1 for循环通过索引定位元素,可以通过索引修改元素值的
* 2 foreach 通过中间变量临时存储元素的值,修改中间变量不会对元素造成修改
* 3 foreach 语法更加简单,没有索引
* 4 当我们仅仅需要数组中的每个元素,不需要修改元素,也不用索引做其他的事,就可以使用 foreach循环
* */
// 修改数组中的元素
/*for (int i = 0; i < darr.length; i++) {
darr[i]*=10;
}*/
for (double v : darr) {
v*=10;
}
// 遍历数组
for(double value:darr){
System.out.println(value);
}
}
}
1.6 常见异常
NullPointerException:空指针异常
ArrayIndexOutOfBoundsException:数组索引越界异常(超过下界或者上界)
public class Test3 {
public static void main(String[] args) {
/*
* 1 动态创建数组时,中括号中放的是数组的长度(容量),容量一定是int类型 和数组的具体类型无关
* 2 数组的长度不能是负数,会出现NegativeArraySizeException(创建时)
* 3 如果数组赋值为null 则代表数组没有在堆内存上创建,此时使用数组会出现异常NullPointerException
* 4 索引如果越界会出现ArrayIndexOutOfBoundsException
* */
String[] arr ={"asdf","qwer","zxcv","aaaa","bbbb","cccc"};
/* System.out.println(arr[-1]);*/
for (int i = 0; i <arr.length ; i++) {
System.out.println(arr[i]);
}
}
}
二、数组的常见应用方式
2.1 数组合并
将两个数整数数组合并成一个数组
public class Test4 {
public static void main(String[] args) {
int[] arr1={1,2,3,4};
int[] arr2={11,22,33,44,55,66,77,88,99,1010,2020};
int[] arr3=combain(arr1,arr2);
// 遍历数组3
for (int i : arr3) {
System.out.println(i);
}
}
// 定义一个方法,将两个整数数组合并并返回
public static int[] combain(int[] arr1,int[] arr2){
int[] arr3=new int[arr1.length+arr2.length];
// 遍历数组1 将元素复制到arr3
for (int i = 0; i <arr1.length ; i++) {
arr3[i]=arr1[i];
}
// 遍历数组2 将元素复制到arr3
for (int i = 0; i <arr2.length ; i++) {
arr3[arr1.length+i]=arr2[i];
}
return arr3;
}
}
2.2 查询数组元素
可以查询指定索引的元素的内容,直接按照索引定位即可;
可以按照指定内容元素的索引,需要逐个比较,直到找到为止,或者比较到数组的末尾也没有找到。
public class Test1 {
public static void main(String[] args) {
char[] arr={'a','c','d','g','v','d','c','a','v','x'};
char element='v';
int index =firstIndexOf(arr,'v');
System.out.println(index);
int index2=lastIndexOf(arr,'v');
System.out.println(index2);
// 判断一个数组中是不是有且仅有一个指定的元素
if(index==-1){
System.out.println("没有");
}else if(index==index2){
System.out.println("一个");
}else{
System.out.println("至少两个");
}
}
// 定义一个方法, 在给定数组中查找目标元素,如果找到了 返回元素的第一次出现的索引 如果没找到返回-1
public static int firstIndexOf(char[] arr,char element){
for (int i = 0; i <arr.length ; i++) {
if(arr[i]==element){
return i;
}
}
return -1;
}
// 定义一个方法, 在给定数组中查找目标元素,如果找到了 返回元素的最后一次出现的索引 如果没找到返回-1
public static int lastIndexOf(char[] arr,char element){
for (int i = arr.length-1; i>=0 ; i--) {
if(arr[i]==element){
return i;
}
}
return -1;
}
}
总结1:数组按照索引查询数据,效率最高;不管索引是哪个,花费的时间是一样的;
原理:分配连续的空间,且每个元素的空间大小是相同的,所以指定索引的元素位置=数组的起始位置+每个元素的大小*索引,无需进行逐个比较。
总结2:数组按照内容查询数据效率低下;
一般需要从第一个元素逐次比较,直到找到位置;或者比较到数组的最后一个元素也没有找到,则确认无该元素。
如果数组的数据是大小有序的,可以通过折半查找的方式来提高查询效率。
3.3 删除数组元素
删除指定索引的元素
public class Test1 {
public static void main(String[] args) {
int[] arr={5,7,3,1,2,6,8,4};
//数组中目前有多少个有效元素
int size =arr.length;
// 删除之前遍历
for (int i = 0; i <size ; i++) {
System.out.println(arr[i]);
}
// 删除指定索引处的元素
int index =3;
// 向前移动元素
for (int i=index;i<arr.length-1;i++){
arr[i]=arr[i+1];
}
// 将最后一个元素置为0
arr[arr.length-1]=0;
// 有效元素减少一个
size--;
System.out.println("___________________");
// 删除之后遍历
for (int i = 0; i <size ; i++) {
System.out.println(arr[i]);
}
}
}
数组的优点:
- 一个数组可以存储多个元素
- 按照索引查询元素效率高
数组的缺点:
- 按照内容查询元素,效率低下(和按照索引插叙相比,相对慢,但是事实上任然很快)
- 进行删除和添加时候需要大量的移动元素,效率低下;
- 长度固定
总结:
1数组是一种引用类型的数据,占用堆内存
2 多个元素在堆内存上是连续的
3 根据索引查询元素效率非常高
4 增删元素效率非常低