1.1、概述

  • Java语言中的数组是一种引用数据类型。不属于基本数据类型。数组的父类是Object类。
  • 数组实际上是一个容器,可以同时容纳多个元素(数组是一个数据的集合)
  • 数组当中可以存储基本数据类型的数据,也可以存储引用数据类型的数据(存的是引用数据类型的内存地址)数组中不能直接存储Java对象
  • 数组因为是引用类型,所以数组对象是在堆内存当中
  • 在Java中,数组一旦创建,长度不可变
  • 数组的分类 包括一维数组、二维数组、三维数组,多维数组…
  • 所有的数组对象都有length属性,用来获取数组中元素的个数
  • Java中的数组要求数组中的元素类型统一,比如int类型数组只能存储int类型,Person类型只能存储Person类型。
  • 数组在内存中存储的时候,数组中的元素内存地址是连续的;数组实际上是一种简单的数据结构。
  • 所有的数组都是拿第一个数组元素的内存地址,作为整个数组对象的内存地址
  • 数组中的每个元素都有索引(下标),索引从0开始,以1递增。最后一个元素的的下标是:length-1
  • 数组的优点和缺点:
  • 优点:查询/检索某个下标上的元素时效率极高。
  • 为什么检索效率高
  1. 每一个元素的内存地址在空间存储上是连续的
  2. 每一个元素类型相同,所以占用空间大小一样
  3. 知道第一个元素内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位元素,所以数组的检索效率是最高的。
  4. 例如数组中存储100个元素,或者100万个元素,在元素查询/检索方面,效率是相同的。因为数组中元素查找的时候不会一个一个去找,而是通过数学表达式计算出来的。(算出一个内存地址,直接定位的)
  • 缺点:
  1. 由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者增加元素的时候,效率极低,因为随机增删元素会涉及到后面元素统一向前或向后位移的操作。
  2. 数组不能存储大量的数据,因为很难在内存空间中,找到一块大的且连续的内存空间。

数组内存结构图

java 数组是类么 java中的数组是对象吗_数据结构

1.2、使用数组

一维数组

  1. 声明数组
数据类型[] 数组名;
// 数据类型可以是基本数据类型也可以是引用数据类型
  1. 初始化数组
//1.静态初始化
int[] array =  {100, 2100, 300, 40};
//2.动态初始化
int[] array = new int[5]; //初始化一个长度为5的整型数组,每个数组元素默认值为0
  1. 取,改数组中的元素
//取数组元素
array[0];   //取数组中第一个元素
array[array.length - 1];    //取数组中最后一个元素
//改数组中元素
array[0] = 11;  //把数组中第一个元素改为11
  1. 遍历数组
//for循环遍历
for(int i = 0; i < array.lrngth; i++){
    System.out.println(array[i]); // 输出数组中的每一个元素
}
//增强for循环
for(int i : array){ //i表示索引
    System.out.println(array[i]);
}
  1. 方法的参数是数组
public class ArrayTest{
    
    
    public static void main(String[] args){
        //通过创建数组,传入方法中
        int[] x = {1,2,3,4,5};
        printArray(x);
        //不能直接传入静态数组,只能这样写
        //printArray({1,2,3,4,5});
        printArray(new int[] {1,2,3,4,5});
        // 传入 动态数组
        printArray(new int[4]); //传入一个长度为4的数组
	}
    
    
    
    public static void printArray(int[] array){  //使用静态方法,不用创建对象,直接调用方法
        for(int i : array){
            System.out.println(array[i]);
		}
    }
}
  1. main方法中String[] args数组

这个数组是留给用户的,用户可以在控制台输入参数,这个参数自动转换为String[] args 数组中的元素

注意使用DOS可以直接加参数,在IDE中需要设置程序参数

例如运行程序 java ArrayTest abc def

那么这个时候JVM会自动将"abc def" 通过空格进行分割,然后从左到右依次存入数组

原先这个数组为空,传入参数后为 args = {“abc”, “def”};

public class ArrayTest{
    
    public static void main(String[] args){
        
        
	}  
}

实例

/*
使用main方法的String[] args数组模拟用户登录
*/
public class Login{
    
    public static void main(String[] args){
        if(args.length != 2){
            System.out.println("使用该系统时请输入系统参数,参数中包括用户名和密码信息,例如:zhangsan 123");
        }
        /*
        程序执行这里说明用户确实输入了用户名和密码
        接下来判断用户名和密码是否正确
        */
        String userName = args[0];
        String userPassword = args[1];
        //if(userName.equals("admin") && userPassword.equals("123456")){
        if("admin".equals(userName) && "123456".equals(userPassword)){ //这样写能够避免空指针异常,即使userName和userPassword为null,也不会报错。建议以后都这样写,比较对象时,使用确定不是空值的对象调用equals()方法
            System.out.println("登录成功!"+userName+"欢迎你!");
        }else{
            System.out.println("验证失败,用户名不存在或者密码错误!");
        }
	}  
}
  1. 数组中存储引用数据类型
public class ArrayTest{
    public static void main(String[] args){
        //创建两个Animal对象并存储到数组中,遍历数组调用方法
        Animal a1 = new Animal();
        Animal a2 = new Animal();
        Animal[] animals = {a1,a2};
        for(int i : animals){
            animals[i].move();
        }
        //创建一个Animal类型的数组,数组当中存储Cat和Bird,
        //因为Cat和Bird继承了Animal类,所以Cat和Bird对象可以存入Animal数组中
        //相当于向上转型,通过调用父类的move方法,动态执行子类的move方法,这就是使用了多态
        Animal[] anis = {new Cat(), new Bird()};
        for(int i : anis){
            //如果调用的方法是父类中存在的方法不需要向下转型,直接父类型引用调用即可
            anis[i].move();
            //如果调用子类中特有方法,就需要向下转型,因为anis数组中可能Cat或者Bird对象,所以需要先进行类型判断,才能进行向下转型。
            if(anis[i] instanceof Cat){
                Cat cat = (Cat)anis[i];
                cat.catchMouse();
            }else if(anis[i] instanceof Bird){
                Bird bird = (Bird)anis[i];
                bird.catchWorm();
            }
        }
    }
}
class Animal{
    public void move(){
        System.out.println("move....");
    }
}
class Cat extends Animal{
    public void move(){
        System.out.println("猫在走猫步");
    }
    public void catchMOuse(){
        System.out.println("猫在抓老鼠");
	}
}
class Brid extends Animal{
    public void move(){
        System.out.println("鸟在飞");
    }
    public void catchWorm(){
        System.out.println("鸟在抓害虫");
    }
}
  1. 一维数组扩容
/*
思想
如果想要扩容的话,重新申请一个大的数组,将已经满的数组的元素,移到大数组中
*/
//注意由于扩容需要用到遍历,将数组中的元素一个一个移动到大数组中去,效率极低。所以尽可能少使用数组扩容,使用数组时最好预估好数组的长度
//当然我们也可以使用System.arraycopy()方法进行数组的拷贝,然后进行扩容,但是这个与上述思想一致,效率也极低
  1. 数组拷贝
public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);
/*
src 拷贝源
dest  目标(源拷贝到这个目标)
srcPos  从源那个位置开始
destPos  从目标那个位置开始拷贝
length   从源中拷贝的个数
*/
int[] src = {1,2,3,4,5};
int[] dest = new int[20];
//拷贝
System.arraycopy(src, 1, dest, 3, 2);
for(int i: dest){
    System.out.println(dest[i]); // 0 0 0 2 3 0 0...
}

1.3、二维数组

  • 二维数组其实是一个特殊的一维数组,特殊在这个一维数组中每一个元素都是一个数组
  • 一维数组可以看作空间中的一条线,二维数组可以看作空间中的一个有限平面,多条平行且紧密接触线做出一个平面,这个比喻也不太恰当,以为在空间中不在同一条直线上的三点可以形成一个平面。
  1. 初始化二维数组
//静态初始化
int[][] a = {
    {1,2,3},
    {4,5,6},
    {7,8,9}
};
//动态初始化二维数组
int[][] a1 = new int[3][4];
  1. 二维数组的length属性
int[][] a = {
    {1,2,3},
    {4,5,6},
    {7,8,9}
};
a.length //表示二维数组中有几个一维数组
a[i].length //表示二维数组中某个一维数组的长度
  1. 二维数组中元素的访问
int[][] a = {
    {1,2,3},
    {4,5,6},
    {7,8,9}
};

/*取二维数组中的元素*/
//取二维数组a中的第一个一维数组
int[] a1 = a[0];
//取第一个一维数组的第一个元素
int a11 = a1[0];
//合并
int a11 = a[0][0];
//取二维数组中第2个一维数组中第三个元素
a[1][2];
  1. 遍历二维数组
String[][] array = {
    {"java", "c++", "html", "go", "python"},
    {"lucy", "tom", "hack"},
    {"1", "2", "3"}
}
for(int i: array){
    for(int j: array[i]){
        System.out.println(array[i][j] + " ");
    }
}
  1. 方法的参数是一个二维数组
public class ArrayTest{
    
    
    public static void main(String[] args){
       String[][] a = {
    		{"java", "c++", "html", "go", "python"},
    		{"lucy", "tom", "hack"},
    		{"1", "2", "3"}
		}
       //遍历数组
        printArray(a);
	}
    
    
    public static void printArray(int[][] array){  //使用静态方法,不用创建对象,直接调用方法
        for(int i: array){
    		for(int j: array[i]){
        		System.out.println(array[i][j] + " ");
    		}
		}
    }
}