0
点赞
收藏
分享

微信扫一扫

Java——数组


文章目录

  • ​​1. 数组概述​​
  • ​​1.1 数组内存图​​
  • ​​1.2 数组的分类​​
  • ​​1.3 数组的四个基本特点​​
  • ​​1.4 数组边界​​
  • ​​1.5 数组这种数据结构的优缺点?​​
  • ​​1.5.1 优点​​
  • ​​1.5.2 缺点​​
  • ​​2. 一维数组​​
  • ​​2.1 声明一维数组​​
  • ​​2.2 创建一维数组​​
  • ​​2.3 初始化一维数组​​
  • ​​1. Java内存分析:​​
  • ​​2. 三种初始化状态:​​
  • ​​1. 静态初始化:​​
  • ​​2. 动态初始化:​​
  • ​​3. 数组的默认初始化​​
  • ​​2.4 使用一维数组​​
  • ​​1. 一维数组的遍历​​
  • ​​For-Each循环​​
  • ​​2. 数组作为方法的参数类型进行传参​​
  • ​​3. main方法上面的"String[ ] args"有什么用?​​
  • ​​4. 数组中存储引用数据类型​​
  • ​​5. 数组扩容​​
  • ​​6. 数组拷贝​​
  • ​​3. 二维数组​​
  • ​​(1). 创建二维数组​​
  • ​​(2). 初始化二维数组​​
  • ​​1. 二维数组的静态初始化和动态初始化​​
  • ​​2. 二维数组length属性​​
  • ​​(3). 使用二维数组​​
  • ​​1. 二维数组的元素访问​​
  • ​​2. 二维数组的遍历​​
  • ​​3. 方法的参数是一个二维数组​​
  • ​​4. 数组模拟题目练习​​
  • ​​(1). 数组模拟栈数据结构​​
  • ​​(2). 二维数组模拟酒店管理系统​​
  • ​​5. Arrays类​​
  • ​​5.1 概述​​
  • ​​5.2 Arrays具有以下常用的功能​​
  • ​​6. 对数组的基本操作​​
  • ​​(1). 遍历数组​​
  • ​​(2). 对数组进行排序​​
  • ​​6.2.1 冒泡排序​​
  • ​​(3). 填充替换数组元素​​
  • ​​(4). 复制数组​​
  • ​​(5). 对数组进行查找​​
  • ​​(6). 稀疏数组​​
  • ​​6.6.1 稀疏数组的介绍​​
  • ​​6.6.2 稀疏数组的应用​​

1. 数组概述

Java语言中的数组是一种引用数据类型。不属于基本数据类型。数组的父类是Object

Java——数组_初始化

  • 数组实际上是一个容器,可以容纳多个元素(数组是相同类型数据的有序集合)
  • 数组当中可以存储“基本数据类型”的数据,也可以存储“引用数据类型”的数据
  • 因为数组是引用数据类型,所以数组对象是在堆内存当中
  • 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。

1.1 数组内存图

  • 数组当中如果存储的是“Java对象”的话,实际上存储的是对象的“引用(内存地址)”,数组不能直接存储java对象
  • 数组一旦创建,在java中规定,长度不可变

数组存储元素的特点:

  • 数组在内存方面存储的时候,数组中的元素内存地址(存储的每一个元素都是有规则的挨着排列的)是连续的。内存地址连续
  • 数组实际上是一种简单的数据结构

所有的数组都是拿“第一个小方框的内存地址”作为整个数组对象的内存地址。(数组中首元素的内存地址作为整个数组对象的内存地址)

原因:数组存储元素的时候,内存地址是连续的,知道了第一个元素的内存地址,
可以算出第二个,以此类推,算出所有的元素内存地址

Java——数组_java_02

1.2 数组的分类

  • 所有的数组对象都有length属性(java自带的)用来获取数组中元素的个数

1.3 数组的四个基本特点

  • 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的

  • 其元素必须是相同类型,不允许出现混合类型

    例如:int类型数组只能存储int类型,Person类型数组只能存储Person类型

  • 数组中的元素可以是任何数据类型,包括基本类型和引用类型

  • 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相对于该对象的成员变量。

数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的

1.4 数组边界

Java——数组_初始化_03

  • 数组中每一个元素都是有下标的,下标从0开始,以1递增,最后一个元素的下标是:length-1
  • 下标的合法区间:[0,length-1],如果越界就会报错;
  • 我们对数组中的元素进行存取的时候,都需要通过下标来进行

public class ArrayDemo03 {
public static void main(String[] args) {
int[] a = new int[2];
System.out.println(a[2]);
}
}

java.lang.ArrayIndexOutOfBoundsException:数组下标越界异常

小结

  • 数组是相同数据类型(数据类型可以为任意类型)的有序集合
  • 数组也是对象。数组元素相对于对象的成员变量
  • 数组长度是确定的,不可变的。如果越界,则报错ArrayIndexOutOfBounds

1.5 数组这种数据结构的优缺点?

1.5.1 优点

查询 / 查找 / 检索某个下标上的元素时效率极高。可以说是查询效率最高的一个数据结构

  • 原因一:每一个元素的内存地址在空间存储上是连续的

  • 原因二:每一个元素类型相同,所以占用空间大小一样

  • 原因三:知道第一个元素内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位元素,所以数组的检索效率最高的

    数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,
    因为数组中元素查找的时候不会一个一个找,是通过数学表达式计算出来的
    (算出内存地址,直接定位)

1.5.2 缺点

  • 第一:由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者增加元素的时候,效率较低,因为随机增删元素会涉及到后面元素统一向前或者向后位移的操作
  • 第二:数组不能存储大数据量,因为很难在内存空间上找到一块特别大的连续的内存空间

注意:对于数组中最后一个元素的增删,是没有效率影响的

2. 一维数组

2.1 声明一维数组

首先必须声明数组变量,才能在程序中使用数组。

下面是声明数组变量的语法:

dataType[] arrayRefVar; //首选的方法
int[] array1
double[] array2
boolean[] array3
String[] array3
Object[] array5

dataType arrayRefVar[]; //效果相同,但不是首选方法

2.2 创建一维数组

声明完数组之后对数据进行创建,分配内存空间

arrayRefVar = new dataType[空间大小];

Java语言也可以使用new操作符将声明和创建二合一创建数组,语法如下:

dataType[] arrayRedVar = new dataType[arraySize];

数组的元素是通过索引访问的,数组索引从0开始

获取素组的长度:

arrays.length

代码里面声明创建数组

package com.pudding.array;

public class ArrayDemo01 {
//变量的类型 变量的名字 = 变量的值;
//数组类型
public static void main(String[] args) {
int[] nums; //1. 声明一个数组
// int nums[];

//分配空间:这里面可以存放10个int类型的数字
nums = new int[10]; //2. 创建数组

//声明和创建合二为一
// int[] nums = new int[10];

//3. 给数组元素中赋值
nums[0] = 1;
nums[1] = 2;
nums[2] = 3;
nums[3] = 4;
nums[4] = 5;
nums[5] = 6;
nums[6] = 7;
nums[7] = 8;
nums[8] = 9;
nums[9] = 10;

//计算所有元素的和
int sum = 0;

//获取数组长度:arrays.length
for (int i = 0; i < nums.length; i++) {
sum = sum + nums[i];
}

System.out.println("总和为:"+sum);
}
}

Java——数组_System_04

2.3 初始化一维数组

1. Java内存分析:

Java——数组_java_05

Java——数组_java_06

2. 三种初始化状态:

1. 静态初始化:

int[] a = {1,2,3};
Man[] mans = {new Man(1,1), new Man(2,2)};

C++风格和Java风格:

C++风格不建议使用:int a[] = {1,100,10,20,55}; 
Java风格: int[] a = {1,100,10,20,55};

public class ArrayTest01 {
public static void main(String[] args) {
//声明一个int类型的数组,使用静态初始化的方式
int[] a = {1,100,10,20,55,689};
//所有的数组对象都有length属性
System.out.println("数组中元素的个数"+a.length);
//数组中每一个元素都有下标
//通过下标对数组中的元素进行存和取
//取(读)
System.out.println("第一个元素 = "+a[0]);
System.out.println("最后一个元素 = "+a[a.length - 1]);

//存(改)
//把第一个元素修改为111
a[0] = 111;
//把最后一个元素修改为0
a[a.length-1] = 0;

System.out.println("第一个元素 = "+a[0]);
System.out.println("最后一个元素 = "+a[5]);

//一维数组怎么遍历?
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]); //i是0到5,是下标
}

//下标为6表示第7个元素,下标越界了,会出现什么异常?
// System.out.println(a[6]); //ArrayIndexOutOfBoundsException 数组下标越界异常

//从最后一个元素遍历到第一个元素
for (int i = a.length - 1; i > 0; i--) {
System.out.println("颠倒顺序输出-->" + a[i]);
}
}
}

2. 动态初始化:

int[] a = new int[2]; //这个的2表示数组的元素个数
//初始化一个5个长度的int类型数组,每个元素默认值0
a[0] = 1;
a[1] = 2;

String[] names = new String[6]; //初始化6个长度的String类型数组,每个元素默认值null

public class ArrayTest02 {
public static void main(String[] args) {
//声明/定义一个数组,采用动态初始化的方式创建
int[] a = new int[4]; //创建长度为4的int数组,数组中每一个元素的默认值是0
//遍历数组
for (int i = 0; i < a.length; i++) {
System.out.println("数组中下标为:"+i+"的元素为"+a[i]);
}

//后期赋值,注意下标别越界
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;

//初始化一个Object类型的数组,采用动态初始化方式
Object[] obj = new Object[3]; //3个长度,动态初始化,所有每个默认值是null
for (int i = 0; i < obj.length; i++) {
System.out.println(obj[i]);
}

//采用静态初始化数组的方式
Object o1 = new Object();
Object o2 = new Object();
Object o3 = new Object();
Object[] objects = {o1,o2,o3};
for (int i = 0; i < objects.length; i++) {
System.out.println(objects[i]); //println默认调用toString方法,
// 输出java.lang.Object@3f99bd52
//java.lang.Object@4f023edb
//java.lang.Object@3a71f4dd
}
//等价于
//Object[] object = {new Object(),new Object(), new Object()};

System.out.println("=========================");

String[] strs = new String[3]; //动态初始化数组
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}

//采用静态初始化的方式
String[] strs2 = {"abc","def","xyz"};
for (int i = 0; i < strs2.length; i++) {
System.out.println(strs2[i]);
}
}
}

Java——数组_java_07

3. 数组的默认初始化

数组是引用类型,它的元素相对于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。

/*
关于每个类型的默认值还有印象?
数据类型 默认值
--------------------
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
boolean false
char \u0000
引用数据类型 null
*/

public class ArrayDemo02 {
public static void main(String[] args) {
//静态初始化:创建+赋值 (这个是基本类型)
int[] a = {1,2,3,4,5,6,7,8};
System.out.println(a[0]);

//动态初始化: 包含默认初始化
int[] b = new int[10];
b[0] = 10;
System.out.println(b[0]);
System.out.println(b[1]); //默认初始化中的值都是0
System.out.println(b[2]);
System.out.println(b[3]);
}
}

什么时候采用静态初始化,什么时候采用动态初始化?

  • 当你创建数组的时候,确定数组中存储哪些具体的元素的时候,采用静态初始化方式
  • 当你创建数组的时候,不确定将来数组中存储哪些数据,你可以采用动态初始化的方式,预先分配内存空间,之后再赋值

2.4 使用一维数组

1. 一维数组的遍历

public class ArreyDemo04 {
public static void main(String[] args) {
int[] arrays = {1,2,3,4,5};

//打印全部的数组元素
for (int i=0; i<arrays.length; i++){
System.out.println(arrays[i]);
}
System.out.println("===============");
//计算所有元素的和
int sum = 0;
for (int i = 0; i < arrays.length; i++) {
sum += arrays[i];
}
System.out.println("sum = "+sum);
System.out.println("===============");

//查找最大元素
int max = arrays[0];

for (int i = 1; i < arrays.length; i++) {
if (arrays[i] > max){
max = arrays[i];
}
}
System.out.println("max = "+max);

}
}

For-Each循环

public class ArrayDemo05 {
public static void main(String[] args) {
int[] arrays = {1,2,3,4,5};

for (int array : arrays) { //增强型的for循环,JDK1.5之后,没有下标
System.out.println(array);
}
}
}

2. 数组作为方法的参数类型进行传参

数组作为方法的参数举例理解

package com.pudding.array;

public class ArrayDemo05 {
public static void main(String[] args) {
int[] arrays = {1,2,3,4,5};

int[] reverse = reverse(arrays);
printArray(reverse);
}

//打印数组元素
public static void printArray(int[] arrays){
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i]+" ");
}
}

//反转数组
public static int[] reverse(int[] arrays){
int[] result = new int[arrays.length];

//反转的操作
for (int i = 0,j=result.length-1; i < arrays.length; i++,j--) {
result[i] = arrays[j];
}

return result;
}

}

当一个方法上,参数类型是一个数组的时候,我们可以采用以下基本传参方式。

public class ArrayTest03 {
//main方法的编写方式,还可以采用C++的语法格式
public static void main(String args[]) {
//调用方法时传一个数组
int[] x = {1,2,3,4};
printArray(x);

//创建String数组
String[] strs= {"abc","def","hehe","haha"};
printArray(strs);

//动态创建数组
String[] strArray = new String[10];
printArray(strArray); //10个null

System.out.println("===============");
printArray(new String[3]);
System.out.println("****************");
printArray(new int[4]);
}

public static void printArray(int[] array){
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}

public static void printArray(String[] args){
for (int i = 0; i < args.length; i++) {
System.out.println("String数组中的元素:"+args[i]);
}
}
}

当一个方法的参数是一个数组的时候,我们还可以采用这种方式传参,采用静态初始化直接传参。

public class ArrayTest04 {
public static void main(String[] args) {
//静态初始化一维数组
int[] a = {1,2,3};
printArray(a);

System.out.println("============");
//没有这种语法
//printArray({1,2,3});
//如果直接传递一个静态数组的话,语法必须这样写
printArray(new int[]{1,2,3});

//动态初始化一维数组
int[] a2 = new int[4];
printArray(a2);

System.out.println("=========");
printArray(new int[2]);
}

//使用静态方法方便啊,不需要new对象了
public static void printArray(int[] array){
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}

3. main方法上面的"String[ ] args"有什么用?

分析 一下:谁负责调用main方法(JVM)

  • JVM调用main方法的时候,会自动传一个String数组过来

public class ArrayTest05 {
//这个方法程序员负责写出来,JVM负责调用的时候一定会传入一个String数组过来
public static void main(String[] args) {
//JVM默认传递过来的这个数组对象长度:默认0
//通过测试得出:args不是null
System.out.println("JVM给传递过来的String数组参数,他这个数组长度是:"+args.length);

/*
//类似:以下代码表示的含义:数组对象创建了,但还是数组中没有任何数据
//String[] strs = new String[0];
String[] strs = {}; //静态初始化,里面没有东西
printlength(strs);

String[] strs2 = new String[1];
System.out.println(strs2[0]); //默认初始化里面的一个数据为null
*/

//遍历数组
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}

public static void printlength(String[] args){
System.out.println(args.length); //长度为0
}
}

这个数组什么时候里面会有值?

  • 其实这个数组是留给用户的,用户可以在控制台上输入参数,这个参数自动会转换为"String[] args"
  • 例如这样的程序:java ArrayTest05 abc def xyz
  • 那么这个时候JVM会自动将"abc def xyz"通过空格的方式进行分离,分离完成之后,自动放到"String[] args"数组当中
  • 所以main方法上面的String[] args数组主要是用来接收用户输入参数的
  • 把abc def xyz 转换为字符串数组:{“abc”,“def”,“xyz”}

CMD中

Java——数组_初始化_08


IDEA中

Java——数组_数组_09


模拟一个系统,假设这个系统要使用,必须输入用户名和密码

public class ArrayTest06 {
//用户名和密码输入到String[] args数组当中
public static void main(String[] args) {
if (args.length != 2){
System.out.println("使用该系统时请输入程序参数,参数中包括用户名和密码信息,例如:zhangsan 123");
return;
}

//程序执行到此处说明用户确实提供了用户名和密码
//接下来你应该判断用户名和密码是否正确
//取出用户名
String username = args[0];
//取出密码
String password = args[1];

//假设用户名是admin,密码是123的时候表示登录成功,其他一律失败
//判断两个字符串是否相等,需要使用equals方法
//if (username.equals("admin") && password.equals("123")){
//下面编写可以避免空指针异常,即使username和password都是null也不会出现空指针异常
if ("admin".equals(username) && "123".equals(password)){
System.out.println("登录成功,欢迎["+username+"]回来");
} else {
System.out.println("验证失败,用户名不存在或者密码错误");
}
}
}

非重点:以后一般都是有界面的,用户可以在界面上输入用户名和密码等参数信息。

4. 数组中存储引用数据类型

一维数组的深入,数组中存储的类型为:引用数据类型

  • 对于数组来说,实际上只能存储java对象的"内存地址",数组中存储的每个元素是“引用”。

package com.array;

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

//array是一个数组
//array[0] 是数组中的一个元素
int[] array = {1,2,3};
for (int i = 0; i < array.length; i++) {
int temp = array[i];
System.out.println(temp);
}

//创建一个Animal类型的数组
Animal a1 = new Animal();
Animal a2 = new Animal();
Animal[] animals = {a1,a2};

//对Animal数组进行遍历
for (int i = 0; i < animals.length; i++) {
/*
Animal a = animals[i];
a.move();
*/
//代码合并
animals[i].move(); //这个move()方法不是数组的,是数组当中Animal对象的move()方法
}

//动态初始化一个长度为2的Animal类型数组
Animal[] ans = new Animal[2];
//创建一个Animal对象,放到数组里的第一个盒子中
ans[0] = new Animal();

//Animal数组中只能存放Animal类型,不能存放Product类型
//ans[1] = new Product()

//Animal数组中可以存放Cat类型的数据,因为Cat是一个Animal
//Cat是Animal子类
ans[1] = new Cat();

//创建一个Animal类型的数组,数组中存储Cat和Brid
Animal[] anis = {new Cat(), new Bird()}; //该数组中存储了两个对象的内存地址
for (int i = 0; i < anis.length; i++) {

/*
//这个取出来的可能是Cat,也可能是Bird,不过肯定是一个Animal
//如果调用的方法是父类中存在的方法不需要向下转型,直接使用父类型引用调用即可
Animal an1 = anis[i];
an1.move();
*/

//Animal中没有sing()方法
//anis[i].sing();

//调用子对象中特有的方法的话,需要向下转型
if (anis[i] instanceof Cat){
Cat cat = (Cat)anis[i];
cat.catchMouse();
} else if (anis[i] instanceof Bird){
Bird bird = (Bird)anis[i];
bird.sing();
}

}

}
}

class Animal{
public void move(){
System.out.println("Animal move...");
}
}

//商品类
class Product{

}

//子类猫
class Cat extends Animal{
public void move(){
System.out.println("Cat move...");
}
//特有的方法
public void catchMouse(){
System.out.println("猫抓老鼠。。");
}
}

//Bird子类
class Bird extends Animal{
public void move(){
System.out.println("Bird fly....");
}
//特有的方法
public void sing(){
System.out.println("鸟儿在歌唱");
}
}

5. 数组扩容

在java开发中,数组长度一旦确定不可变,那么数组满了的怎么办?

  • java中数组的扩容是:先新建一个大容量的数组,然后将小容量的数组中的数据一个一个拷贝到大数组当中,小数组对象被垃圾回收。
  • 结论:数组扩容效率比较低,因为涉及到拷贝的问题。所以在以后的开发中请注意:尽可能少的进行数组的拷贝。
  • 可以在创建数组对象的时候预估以下多长合适,最好预估准确,这样可以减少数组的扩容次数。提高效率
  • Java——数组_数组_10


  • Java——数组_System_11


6. 数组拷贝

package com.array;

public class ArrayTest08 {
public static void main(String[] args) {
//java中的数组是怎么进行拷贝的?
//System.arraycopy(5个参数);

//拷贝源(从数组中拷贝)
int[] src = {1,11,22,3,4};

//拷贝目标(拷贝到这个目标数组上)
int[] dest = new int[20]; //动态初始化一个长度为20的数组,每一个元素的默认值为0

/*
//调用JDK,System类中的arraycopy方法,来完成数组的拷贝
System.arraycopy(src, 1, dest, 3, 2);

//遍历目标数组
for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]); //0 0 0 11 22 0 ...0
}
*/

System.arraycopy(src, 0, dest, 0, src.length);
for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]);
}

//数组中存储的元素是引用类型的话,也可以拷贝
String[] strs = {"hello","world","study","java","oracle","mysql","jdbc"};//字符串数组
String[] newStrs = new String[20];
System.arraycopy(strs,0,newStrs,0,strs.length);

for (int i = 0; i < newStrs.length; i++) {
System.out.println(newStrs[i]); //hello world study java oracle mysql jdbc null...
}

Object[] objs = {new Object(), new Object(), new Object()};
Object[] newObjs = new Object[5];
//这里拷贝的时候,是拷贝对象的地址
System.arraycopy(objs,0,newObjs,0,objs.length);
for (int i = 0; i < newObjs.length; i++) {
System.out.println(newObjs[i]); //默认调用toString方法
/*
输出结果:
java.lang.Object@3f99bd52
java.lang.Object@4f023edb
java.lang.Object@3a71f4dd
null
null
*/
}

}
}

Java——数组_初始化_12

3. 二维数组

多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,特殊在,这个一维数组当中的每一个元素都是一个一维数组

  • 三位数组是一个特殊的二维数组,特殊在这个二维数组中每一个元素都是一个一维数组
  • 实际开发中使用最多的就是一维数组,二维数组很少使用,三位数组几乎不用

Java——数组_初始化_13


Java——数组_初始化_14

(1). 创建二维数组

int a[][] = new int[2][5]

以上二维数组a可以看成一个两行五列的数组

package com.pudding.array;

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

//[4][2]
/*
1,2 array[0]
2,3 array[1]
3,4 array[2]
4,5 array[3]
*/
int[][] array = {{1,2},{2,3},{3,4},{4,5}};

printArray(array[0]); //打印的是二维数组中的第一行的一维数组

System.out.println();
System.out.println(array[0][0]); //二维数组的第一行第一列的值
System.out.println(array[0][1]);

for (int i = 0; i < array.length; i++) { //外面空间数组长度
for (int j = 0; j < array[i].length; j++) { //每一个一维数组的长度
System.out.println(array[i][j]);
}
}


}

//打印数组元素
public static void printArray(int[] arrays){
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i]+" ");
}
}
}

(2). 初始化二维数组

1. 二维数组的静态初始化和动态初始化

静态初始化

int[][] arr = {
{112,2.3},
{3,43},
{34,23,3,5}
};

Object[][] arr = {
{new Object(),new Object()},
{new Object(),new Object(),new Object()},
{new Object(),new Object()}
};

动态初始化

int[][] arr = new int[3][4];   //三行四列
Object[][] arr = new Object[4][4]; //四行四列
Animal[][] arr = new Animal[2][2];
//animal类型数组,里面可以存储animal类型对象,以及animal类型子类型

2. 二维数组length属性

package com.array;

public class ArrayTest09 {
public static void main(String[] args) {
//一维数组
int[] array = {100,200,300};
System.out.println(array.length); //3个

//二维数组
//以下代码当中:里面是4个一维数组
int[][] a = {
{100,200,300},
{30,20,40,50,60},
{6,7,9,1},
{0}
};
System.out.println(a.length); //4个元素
System.out.println(a[0].length); //3个元素
System.out.println(a[1].length); //5个元素
System.out.println(a[3].length); //1个元素
}
}

(3). 使用二维数组

1. 二维数组的元素访问

package com.array;

/*
关于二维数组中元素的:读和该
a[二维数组中的一维数组的下标][一维数组的下标]
a[0][0]:表示第一个一维数组中的第一个元素

注意对于a[3][100]来说,其中a[3]是一个整体,[100]是前面a[3]执行结束的结果然后再下标100.
*/
public class ArrayTest10 {
public static void main(String[] args) {
//二维数组
int[][] a = {
{11,23,54},
{100,23,432,234},
{0}
};


//请取出以上二维数组中的第一个一维数组
int[] 我是第1个一维数组 = a[0];
int 我是第1个一维数组中的第1个元素 = 我是第1个一维数组[0];
System.out.println(我是第1个一维数组中的第1个元素); //11

//合并以上代码
System.out.println(a[0][0]); //11

//注意别越界
// System.out.println(a[2][1]); //ArrayIndexOutOfBoundsException

//取出第二个一维数组当中第三个元素
System.out.println("第二个数组中第三个元素:"+a[1][2]); //432

//改
a[2][0] = 11111;
System.out.println(a[2][0]); //11111
}
}

2. 二维数组的遍历

package com.array;

public class ArrayTest11 {
public static void main(String[] args) {
//二维数组
String[][] array = {
{"java","oracle","c++","c#"},
{"张三","李四","王五"},
{"lucy","jack","rose"}
};

//遍历二维数组
for (int i = 0; i < array.length; i++) { //外层循环3次(负责纵向,也就是外面的一维数组)
/*
String[] 一维数组 = array[i];
//负责遍历一维数组
for (int j = 0; j < 一维数组.length; j++) {
System.out.println(一维数组[j]+"");
}
*/

//合并代码
//内存循环负责输出一行,负责遍历二维数组里面的一维数组
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]+" ");
}

//换行
System.out.println();
}
}
}

3. 方法的参数是一个二维数组

package com.array;

/*
* 动态初始化二维数组
* */
public class ArrayTest12 {
public static void main(String[] args) {
//3行4列:3个一维数组,每一个一维数组当中4个元素
int[][] array = new int[3][4];

//二维数组遍历
/*
for (int i = 0; i < array.length; i++) { //循环3次
for (int j = 0; j < array[i].length; j++) { //循环4次
System.out.print(array[i][j]+" ");
}
System.out.println();
}
*/

//静态初始化
int[][] a = {
{1,2,3,4},
{4,5,6,76},
{1,23,4}
};
printArray(a);

//没有这种语法
//printArray({{1,2,3,4}, {4,5,6,76}, {1,23,4}});

//可以这样写
printArray(new int[][]{{1,2,3,4}, {4,5,6,76}, {1,23,4}});
}

public static void printArray(int[][] array){
//二维数组遍历
for (int i = 0; i < array.length; i++) { //循环3次
for (int j = 0; j < array[i].length; j++) { //循环4次
System.out.print(array[i][j]+" ");
}
System.out.println();
}
}
}

4. 数组模拟题目练习

(1). 数组模拟栈数据结构

编写程序,使用一维数组,模拟数据结构

要求:
1. 这个栈可以存储java中的任何引用类型的数据
2. 在栈中提供push方法模拟压栈(栈满了,要有提示信息)、
3. 在栈中提供pop方法模拟弹栈(栈空了,也要有提示信息)
4. 编写测试程序,new栈对象,调用push、pop方法来模拟压栈弹栈的动作

  • Object[]这是一个万能的口袋,这个口袋中可以装任何引用数据类型的数据

package com.array.homework;
/*
编写程序,使用一维数组,模拟数据结构
要求:
1. 这个栈可以存储java中的任何引用类型的数据
2. 在栈中提供push方法模拟压栈(栈满了,要有提示信息)、
3. 在栈中提供pop方法模拟弹栈(栈空了,也要有提示信息)
4. 编写测试程序,new栈对象,调用push、pop方法来模拟压栈弹栈的动作
5. 假设栈的默认初始化容量是10。(请注意无参数构造方法的编写方式)
*/
public class MyStack {
//向栈当中存储元素,使用一维数组,存到栈中,表示存储到数组中,数组是一个容器
//选择Object类型数组,可以存储java中任何引用类型的数据
private Object[] elements;
private int index; //采用-1表示栈帧指向了顶部元素

/*压栈,压入元素obj*/
public void push(Object obj){
if (index >= elements.length - 1){
System.out.println("压栈失败,栈已满");
return;
}
//程序执行到这来说明栈没满
index++;
elements[index] = obj;
//所有sout()方法执行时,如果输出引用的话,自动调用引用的toString()方法
System.out.println("压栈"+obj+"元素成功,栈帧指向"+index);
}

/*弹栈,每次弹一个元素*/
public Object pop(){
if (index < 0){
System.out.println("弹栈失败,栈已空");
return null;
}
System.out.println("弹栈"+elements[index]+"元素成功,栈帧指向"+index);
index--;
return elements[index+1];
}


public MyStack() {
//动态初始化
this.elements = new Object[10];
this.index = -1;
}


//封装:第一步:属性私有化,第二步:提供set和get方法
public Object[] getElements() {
return elements;
}

public void setElements(Object[] elements) {
this.elements = elements;
}
}


package com.array.homework;

public class MyStackTest {
public static void main(String[] args) {
MyStack stack = new MyStack();
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());

stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
}
}
压栈java.lang.Object@154617c元素成功,栈帧指向0
压栈java.lang.Object@a14482元素成功,栈帧指向1
压栈java.lang.Object@140e19d元素成功,栈帧指向2
压栈java.lang.Object@17327b6元素成功,栈帧指向3
压栈java.lang.Object@14ae5a5元素成功,栈帧指向4
压栈java.lang.Object@131245a元素成功,栈帧指向5
压栈java.lang.Object@16f6e28元素成功,栈帧指向6
压栈java.lang.Object@15fbaa4元素成功,栈帧指向7
压栈java.lang.Object@1ee12a7元素成功,栈帧指向8
压栈java.lang.Object@10bedb4元素成功,栈帧指向9
压栈失败,栈已满
弹栈java.lang.Object@10bedb4元素成功,栈帧指向9
弹栈java.lang.Object@1ee12a7元素成功,栈帧指向8
弹栈java.lang.Object@15fbaa4元素成功,栈帧指向7
弹栈java.lang.Object@16f6e28元素成功,栈帧指向6
弹栈java.lang.Object@131245a元素成功,栈帧指向5
弹栈java.lang.Object@14ae5a5元素成功,栈帧指向4
弹栈java.lang.Object@17327b6元素成功,栈帧指向3
弹栈java.lang.Object@140e19d元素成功,栈帧指向2
弹栈java.lang.Object@a14482元素成功,栈帧指向1
弹栈java.lang.Object@154617c元素成功,栈帧指向0
弹栈失败,栈已空

(2). 二维数组模拟酒店管理系统

Java——数组_System_15

package com.array.homework;

import java.util.Scanner;

/*为某个酒店编写程序:酒店管理系统,模拟订房、退房、打印所有房间状态等功能
* 1. 该系统的用户是酒店前台
* 2. 酒店使用一个二维数组来模拟,"Room[][] rooms"
* 3. 酒店中的每一个房间应该是一个java对象:room
* 4. 每一个房间Room应该有:房间编号、房间类型、房间是否空闲
* 5. 系统应该对外提供的功能:
* 可以预定房间:用户输入房间编号,订房
* 可以退房:用户输入房间编号、退房
* 可以查看所有房间的状态:用户输入某个指令应该可以查看所有房间状态*/
public class HotelMgtSystem {
public static void main(String[] args) {

//创建酒店对象
Hotel hotel = new Hotel();

System.out.println("欢迎使用酒店管理系统,请认真阅读以下使用说明");
System.out.println("请输入对应的功能编号:[1]表示查看房间列表;[2]表示订房;[3]表示退房;[0]表示退出系统");
Scanner scanner = new Scanner(System.in);

while (true){
System.out.print("请输入功能编号:");
int i = scanner.nextInt();
if (i == 1){
hotel.print();
}else if (i == 2){
System.out.print("请输入订房编号:");
int roomNo = scanner.nextInt();
hotel.order(roomNo);
}else if (i == 3){
System.out.print("请输入退房编号:");
int roomNo = scanner.nextInt();
hotel.exit(roomNo);
}else if (i == 0){
System.out.println("再见,欢迎下次再来!");
return;
}else {
System.out.println("输入编号有误,请重新输入!");
}
}
}
}

package com.array.homework;

/*
* 酒店对象,酒店中有二维数组,二维数组模拟大厦所有房间*/
public class Hotel {
private Room[][] rooms;

//通过构造方法盖楼

public Hotel() {
//一共有几层,每层的房间类型是什么,每个房间的编号是什么
//动态初始化
rooms = new Room[3][10]; //3行10列,3层楼,每层10个房间
for (int i = 0; i < rooms.length; i++) { //i是下标,i+1是楼层
for (int j = 0; j < rooms[i].length; j++) {
if (i == 0){
rooms[i][j] = new Room((i+1)*100+j+1,"单人间",true);
}else if (i == 1){
rooms[i][j] = new Room((i+1)*100+j+1,"标准间",true);
}else if (i == 2){
rooms[i][j] = new Room((i+1)*100+j+1,"总统套房",true);
}

}
}
}

//酒店对象上提供一个打印房间列表的方法
public void print(){
//打印所有房间状态,就是遍历二维数组
for (int i = 0; i < rooms.length; i++) {
for (int j = 0; j < rooms[i].length; j++) {
Room room = rooms[i][j];
System.out.print(room.toString());
}
System.out.println();
}
}

/**
* 订房方法
* @param roomNo 传递一个房间编号
*/
public void order(int roomNo){
//最主要就是将房间对象的status修改为false
//通过房间编号演算出下标,获取房间对象
Room room = rooms[roomNo/100 - 1][roomNo%100 - 1];
room.setStatus(false);
System.out.println(roomNo + "已定房!");
}

/*
* 退房
* */
public void exit(int roomNo){
Room room = rooms[roomNo/100 - 1][roomNo%100 - 1];
room.setStatus(true);
System.out.println(roomNo + "已退房!");
}
}

package com.array.homework;

public class Room extends Object{
/* 房间编号
一楼:101 102 103...
二楼:201....
* */
private int no;
/*
* 房间类型:标准间、单人间、总统套房*/
private String type;
/*
* 房间状态
* true表示空闲,房间可以被预定
* false表示占用,房间不能被预定
* */
private boolean status;

public Room() {

}

public Room(int no, String type, boolean status) {
this.no = no;
this.type = type;
this.status = status;
}

public int getNo() {
return no;
}

public void setNo(int no) {
this.no = no;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public boolean getStatus() {
return status;
}

public void setStatus(boolean status) {
this.status = status;
}

//equals方法重写
//比较两个对象是否相同,这个是程序员自己定
public boolean equals(Object obj) {
if (null == obj || !(obj instanceof Room)) return false;
if (this == obj) return true;
Room room = (Room)obj;
//当前房间编号 等于 传过来的房间对象的房间编号。认为是同一个房间
return this.getNo() == room.getNo();
}

//toString方法重写(可以不要看对象的内存地址)
//将Java对象转换为字符串形式,程序员自己定
public String toString() {
//把一个变量塞到一个字符串当中,口诀:加一个双引号,双引号中间加两个加号,两个加号中间加变量名
return "["+no+","+type+","+(status ? "空闲" : "占用")+"]";
}

/*public static void main(String[] args) {
Room room= new Room(101,"单人间",false);

//new一个room对象,是一个引用
//println(引用),会自动调用引用的toString()方法
System.out.println(room);
}*/
}

5. Arrays类

5.1 概述

数组工具类java.util.Arrays

由于数组对象本身并没有什么方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作

Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而不用使用对象来调用(注意:是不用,而不是不能)

  • Java为什么好学,因为Java有一套强大的类库,牛人都写好了,可以直接拿过来调用
  • Java——数组_初始化_16


5.2 Arrays具有以下常用的功能

  • 给数组赋值:通过fill方法
  • 对数组排序:通过sort方法,按升序
  • 比较数组:通过equals方法比较数组中元素值是否相等
  • 查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作

package com.pudding.array;

import java.util.Arrays;

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

int[] a = {1,23,43,6,12390,1323,23};

System.out.println(a); //对象的哈希code[I@154617c

//打印数组元素Arrays.toString
System.out.println(Arrays.toString(a));
printArray(a);

Arrays.sort(a); //数组进行排序: 顺序
System.out.println(Arrays.toString(a));

Arrays.fill(a,2,4,0); //数组填充(将下标2-4填充为0)
System.out.println(Arrays.toString(a));

}

//重复造轮子
public static void printArray(int[] a){
for (int i = 0; i < a.length; i++) {
if (i==0){
System.out.print("[");
}

if (i==a.length-1){
System.out.print(a[i]+"]");
}else {
System.out.print(a[i]+", ");
}
}
}
}

6. 对数组的基本操作

(1). 遍历数组

(2). 对数组进行排序

十大经典排序算法

6.2.1 冒泡排序

冒泡排序无疑是最为出名的排序算法之一,总共有八大排序

Java——数组_初始化_17


冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人人尽皆知。

我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度0(n2)

冒泡排序

package com.pudding.array;

import java.util.Arrays;

public class ArrayDemo08 {
public static void main(String[] args) {
int[] a = {1,2,6,23,12,33,-6};
int[] sort = sort(a); //调用完我们自己写的排序方法以后,返回一个排序后的数组

System.out.println(Arrays.toString(sort));

}

//冒泡排序
//1. 比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置
//2. 每一次比较,都会产生出一个最大,或者最小的数字;
//3. 下一轮则可以少一次排序
//4. 依次循环,直到结束!

public static int[] sort(int[] array){
//临时变量
int temp = 0;

//外层循环,判断我们这个要走多少次;
for (int i = 0; i < array.length-1; i++) {
//内存循环,比较判断两个数,如果第一个数比第二个数大,则交换位置
for (int j = 0; j < array.length-1-i; j++) {
if (array[j+1] < array[j]){
temp = array[j+1];
array[j+1] = array[j];
array[j] = temp;
}
}
}

return array;

}
}

或者这样也行
public class ArraysTest01 {

public static void main(String[] args) {
int[] arr = {2,4,5,67,76};

for (int i = arr.length-1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (arr[j] > arr[j+1]){
int temp;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}

for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}

(3). 填充替换数组元素

(4). 复制数组

(5). 对数组进行查找

(6). 稀疏数组

需求:编写五子棋游戏中,有存盘退出和续上盘的功能

Java——数组_数组_18


其中黑子代表1,白子代表2,因为该二维数组的很多默认值0,因此记录了很多没有意义的数据。

解决方式:通过稀疏数组(压缩)

6.6.1 稀疏数组的介绍

当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。

稀疏数组的处理方式:

  • 记录数组一共有几行几列,有多少个不同值
  • 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模

如下图:左边是原始数组,右边是稀疏数组

Java——数组_java_19

6.6.2 稀疏数组的应用

package com.pudding.array;

public class ArrayDemo09 {
public static void main(String[] args) {
//1. 创建一个二维数组11*11, 0:没有棋子,1:黑棋,2:白棋

int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 2;
//输出原始的数组
System.out.println("输出原始的数组");

for (int[] ints : array1) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}

System.out.println("===================");
//转换为稀疏数组保存
//获取有效值的个数
int sum = 0;
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (array1[i][j]!=0){
sum++;
}
}
}
System.out.println("有效值的个数:"+sum);

//1. 创建一个稀疏数组的数组
int[][] array2 = new int[sum+1][3];
array2[0][0] = 11; //代表数组有多少行
array2[0][1] = 11; //代表数组有多少列
array2[0][2] = sum; //代表有效值的个数

//遍历原来的二维数组,将非零的值存放到稀疏数组中
int count = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if (array1[i][j]!=0){
count++;
array2[count][0] = i; //获取原数组位置赋值给稀疏数组的第count行第1列
array2[count][1] = j;
array2[count][2] = array1[i][j];//或者原数组的值赋值给稀疏数组的第count行第3列
}
}
}

//输出稀疏数组
System.out.println("稀疏数组");

for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i][0]+"\t"
+array2[i][1]+"\t"
+array2[i][2]+"\t");

}

System.out.println("===================");
System.out.println("还原数组");
//1. 读取稀疏数组的值
int[][] array3 = new int[array2[0][0]][array2[0][1]];

//2. 给其中的元素还原它的值
for (int i = 1; i < array2.length; i++) {
array3[array2[i][0]][array2[i][1]] = array2[i][2];
}

//打印
System.out.println("输出还原的数组");

for (int[] ints : array3) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}
}
}

结果如下:

输出原始的数组
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
===================
有效值的个数:2
稀疏数组
11 11 2
1 2 1
2 3 2
===================
还原数组
输出还原的数组
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0




举报

相关推荐

java数组

JAVA数组

数组(java)

Java 数组

java 数组

【java】数组

【Java】数组

Java数组

java——数组

0 条评论