数组
(1)、是一种引用数据类型,不属于基本数据类型。父类是Object。
(2)、是一个容器。可以容纳多个元素(数组是一个数据的集合)
(3)、数组当中可以存储“基本数据类型”的数据也可以存储“引用数据类型” 的数据
例:
package javaCoreTest;
//数组中存储引用数据类型
public class ArrayTest06 {
public static void main(String [] args) {
Animal a1 = new Animal();
Animal a2 = new Animal();
Animal [] animal = {a1, a2};
//对animal数组进行遍历
for(int i = 0; i < animal.length; i++) {
animal[i].move();
}
Animal [] aa = {new Cat(), new Bird()};
for(int i = 0; i < aa.length; i++) {
//这个取出的可能是Cat,也可能是Bird,不过肯定是一个Animal
//如果调用的方法是父类中存在的方法不需要向下转型。直接使用父类型引用调用即可
aa[i].move();
//如果调用子类特有的方法需要向下转型
if(aa[i] instanceof Cat) {
Cat cat = (Cat)aa[i];
cat.catMouse();
}else if(aa[i] instanceof Bird) {
Bird bird = (Bird)aa[i];
bird.birdSinging();
}
}
}
}
class Animal{
public void move() {
System.out.println("Animal move....");
}
}
class Cat extends Animal{
public void move() {
System.out.println("猫在走猫步");
}
public void catMouse() {
System.out.println("猫吃老鼠");
}
}
class Bird extends Animal{
public void move() {
System.out.println("Bird fly!");
}
public void birdSinging() {
System.out.println("Bird is singing.");
}
}
运行结果:
Animal move....
Animal move....
猫在走猫步
猫吃老鼠
Bird fly!
Bird is singing.
(4)、数组对象存储在堆内存当中。
(5)、数组当中如果存储的是“Java对象”的话,实际上存储的是对象的“引用(内存地址)”,数组是不能直接存储Java对象的。
(6)、数组一旦创建,在Java中规定,长度不可变。
(7)、所有的数组都有length属性(Java自带的),用来获取数组中元素的个数
(8)、Java中的数组要求数组中元素类型统一。比如int类型数组只能存储int类型,Person类型数组只能存储Person类型。
(9)、数组元素内存地址连续。
(10)、数组中首元素的内存地址作为整个数组对象的地址
(11)、数组中的每个元素都有下标,下标从零开始,以1递增,最后一个元素的下标是:length-1
例:
package javaCoreTest;
public class ArrayTest01 {
public static void main(String [] args) {
//使用静态初始化的方法声明一个数组
int [] a = {1, 2, 78, 99, 100};
//所有数组都有length属性
System.out.println("数组中的元素个数:" + a.length);//数组中的元素个数:5
//通过下标对数组中的元素进行取
System.out.println("第一个元素:" + a[0]);//第一个元素:1
System.out.println("最后一个元素:" + a[a.length - 1]);//最后一个元素:100
//通过下标对数组中的元素进行存(改)
a[0] = 111;
a[a.length - 1] = 0;
System.out.println("第一个元素:" + a[0]);//第一个元素:111
System.out.println("最后一个元素:" + a[a.length - 1]);//最后一个元素:0
//数组正序遍历
for(int i = 0; i<a.length; i++) {
System.out.print(" " + a[i]);// 111 2 78 99 0
}
System.out.println();
//数组逆序遍历
for(int i = a.length - 1; i >= 0; i--) {
System.out.print(" " + a[i]);//0 99 78 2 111
}
}
}
(12)、数组这种数据结构的优点和缺点是什么?
**优点: 查询/查找/检索某个下标上的元素时效率极高,可以说是效率最高的一个数据结构。 为什么效率高?【面试时会问】 -每一个元素的内存地址在空间存储上是连续的 -每一个元素类型相同,所以占用空间大小一样
-知道第一个元素内存地址,知道每个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位元素,所以数组的检索效率是最高的。注:数组中存储100个元素和存储100万个元素,在元素的查找方面效率是相同的,因为数组中元素查找的时候不会一个一个找,是通过数学表达式计算出来的。
**缺点:
-由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者增加元素的时候,效率较低,因为随机增删元素会涉及到后面元素统一想想或向后位移的操作。注意:对于数组最后一个元素的增删是没有效率影响的。
-数组不能存储大数据量。 为什么?
因为很难在内存空间上找到一块特别大的连续内存空间
(12)、怎么声明/定义一个一维数组?
-
语法格式:
int [] array1; doouble [] array2; String [] array3; boolean [] array4;
(13)、怎么初始化一个一维数组?
-
包括两种方法:
-静态初始化 语法格式:int [] array = {100, 2100, 01, 03}; -动态初始化 语法格式:int [] array = new int[5]; //这里的5表示数组的元素个数, //初始化一个5个长度的int类型数组,每个元素默认值为0 String [] array = new String[6]; //初始化6个长度的String类型数组,每个元素默认值null 例:
package javaCoreTest;
//动态初始化数组
public class ArrayTest02 {
public static void main(String [] args) {
//声明/定义一个数组,采用动态初始化的方式创建
int [] a = new int [4];
//遍历数组
for(int i = 0; i < a.length; i++) {
System.out.println("数组中下标为" + i + "的元素为:" + a[i]);
}
//初始化一个Object类型的数组,采用动态初始化的方式
Object [] obj = new Object[3];//每个元素默认值是null
for(int i = 0; i < obj.length; i++) {
System.out.println(obj[i]);
}
}
}
package javaCoreTest;
//当一个方法的参数是一个数组的时候,可以采用这种方法
public class ArrayTest03 {
public static void main(String [] args) {
//采用静态初始化一维数组
int [] x = {1, 2, 3, 4};
printArray(x);//1234
System.out.println("------------------------------------");
//如果直接传递一个静态数组,语法必须这样写
printArray(new int [] {1, 2, 3});//123
System.out.println("------------------------------------");
//采用动态初始化一维数组
int [] a = new int [4];
printArray(a);//0000
System.out.println("=========================");
printArray(new int [3]);//000
}
public static void printArray(int [] array) {
for(int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
(14)、什么时候才要静态初始化方式?什么时候采用动态初始化方式?
-
-当创建数组的时候, 确定数组中存储具体的元素时,采用静态初始化方式。
-
-当创建数组的时候,不确定数组中存储哪些数据,可以采用动态初始化的方式,预先分配内存空间。
(15)、关于一维数组的扩容
先新建一个大容量的数组,然后将小容量的数组中的数据一个一个地拷贝到大数组中。
例:
package javaCoreTest;
//数组拷贝
public class ArrayTest07 {
public static void main(String [] args) {
//System.arraycopy(5个参数)
//拷贝源(从这个数组中拷贝)
int [] src = {1, 11, 22, 3, 4};
//拷贝目标(拷贝到这个目标数组上)
int [] dest = new int [20];
//调用JDK System类中的arraycopy方法
System.arraycopy(src, 1, dest,3, 2);
//遍历
for(int i = 0; i < dest.length; i++) {
System.out.print(" " + dest[i]);
// 0 0 0 11 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
}
System.out.println();
//数组中存储字符串引用时
String [] strs = {"hello", "world", "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.print(" " + newStrs[i]);
//hello world java oracle mysql jdbc null null null null null null null null null null null null null null
}
}
}
结论:数组扩容效率较低,因为涉及到拷贝的问题。在以后的开发中注意:尽可能地减少数组拷贝。
(16)、二维数组
-
-二维数组其实是一个特殊的一维数组,特殊在这个二维数组当中的每一个元素是一个一维数组。
-
-二维数组静态初始化:
int[][]array = {{1, 2, 3}, {2, 3, 4, 5}, {0, 0}};
注意大括号后面的引号
package javaCoreTest;
public class ArrayTest08 {
public static void main(String [] args) {
//一维数组
int [] array = {100, 200, 300};
//二维数组
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[2].length);//4
System.out.println(a[3].length);//1
}
}
(17)、关于二维数组中元素的读和取
a[二维数组中一维数组的下标][一维数组的下标]
例:a[0][0]:表示一个一维数组中的第一个元素
package javaCoreTest;
//关于二维数组中元素的读和改
public class ArrayTest09 {
public static void main(String [] args) {
int [][] a = {
{34, 4, 65},
{100, 200, 300, 111},
{0}
};
//取出二维数组中的第一个一维数组
int [] a0 = a[0];
//第一个一维数组中的第一个元素
int a00 = a0[0];
System.out.println(a00);//34
//合并以上代码
System.out.println(a[0][0]);//34
//改
a[2][0] = 1111;
System.out.println(a[2][0]);//1111
}
}
遍历:
package javaCoreTest;
//遍历二维数组
public class ArrayTest10 {
public static void main(String [] args) {
//静态初始化二维数组
String [][] array = {
{"java", "oracle", "c++", "C#"},
{"zhangsan", "lisi", "wangtiechui"},
{"lucy", "jack", "rose"}
};
//遍历二维数组
for(int i = 0; i < array.length; i++) {
for(int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
//动态初始化二维数组
int [][] a = new int[3][4];
for(int i = 0; i < a.length; i++) {
for(int j = 0; j < a[i].length; j++) {
System.out.print(a[i][j] + " ");
}
System.out.println();
}
}
}
运行结果:
java oracle c++ C#
zhangsan lisi wangtiechui
lucy jack rose
0 0 0 0
0 0 0 0
0 0 0 0
(18)、数组常见的算法
-
排序算法:
冒泡排序 选择排序
-
查找算法:
二分法查找
算法实际上在Java中不需要精通,因为Java中已经封装好了,要排序调用方法就行,
例如:
Java中提供了一个数组工具类:java.util.Arrays
Arrays是一个工具类。
其中有一个sort()方法,可以排序,静态方法,直接使用类名调用就行。
例:
package javaCoreTest;
import java.util.Arrays;
/**
* 使用以下SUN公司提供的数组工具类:java.util.Arrays;
* @author SKX
*
*/
public class ArraysTest01 {
public static void main(String [] args) {
int [] arr = {1, 55, 78, 2, 99, 0, 100};
Arrays.sort(arr);
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
(19)、
/*
- main方法上面的“String [] args"有什么用?
- 分析以下:谁负责调用main方法(JVM)
- JVM调用main方法的时候,会自动传一个String数组过来
*/
package javaCoreTest;
public class ArrayTest04 {
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[] args"
//例如:这样的运行程序:java ArrayTest04 abc def xyz
//那么这个时候JVM会自动将abc def xyz通过空格的方式进行分离,分离完成之后,自动放至String [] args数组当中。
//把abc def xyz转换成字符串数组:{"abc", "def", "xyz"}
//如何输入元素运行:
//Run-->run Configurations-->arguments-->在program arguments中输入元素
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
}
}
例: * 模拟一个系统,假设这个系统要使用,必须输入用户名和密码
package javaCoreTest;
/*
* 模拟一个系统,假设这个系统要使用,必须输入用户名和密码
*/
public class ArrayTest05 {
//用户名和密码输入到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")) {
//以下的语句可以避免空指针异常(编程经验)
if("admin".equals(username) && "123".equals(password)) {
System.out.println("登录成功");
}
else {
System.out.println("用户名或密码不正确");
}
}
}
*表示栈的压栈、弹栈动作,用一维数组
package javaCoreTest;
public class ArrayTest11 {
public static void main(String [] args) {
ArrayTest11 arr = new ArrayTest11();
arr.push(new Object());
arr.push(new Object());
arr.push(new Object());
arr.push(new Object());
arr.push(new Object());
arr.push(new Object());
arr.push(new Object());
arr.push(new Object());
arr.push(new Object());
arr.push(new Object());
arr.push(new Object());
arr.pop();
arr.pop();
arr.pop();
arr.pop();
arr.pop();
arr.pop();
arr.pop();
arr.pop();
arr.pop();
arr.pop();
arr.pop();
}
private Object[] elements;
private int index;
//private int index = 0;//表示栈帧指向了顶部元素的上方
//private int index = -1;//表示栈帧指向了顶部元素
public ArrayTest11() {
this.elements = new Object[10];
this.index = -1;
}
public void push(Object obj) {
if(this.index >= this.elements.length - 1) {
System.out.println("压栈失败,栈已满!");
return ;
}
index++;
elements[index] = obj;
System.out.println("压栈成功");
}
public void pop(){
if(index < 0) {
System.out.println("弹栈失败,栈已空!");
return;
}
System.out.println("弹栈成功,元素为:" + elements[index]);
index--;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public Object[] getElements() {
return elements;
}
public void setElements(Object[] elements) {
this.elements = elements;
}
}
运行结果:
压栈成功
压栈成功
压栈成功
压栈成功
压栈成功
压栈成功
压栈成功
压栈成功
压栈成功
压栈成功
压栈失败,栈已满!
弹栈成功,元素为:java.lang.Object@15db9742
弹栈成功,元素为:java.lang.Object@6d06d69c
弹栈成功,元素为:java.lang.Object@7852e922
弹栈成功,元素为:java.lang.Object@4e25154f
弹栈成功,元素为:java.lang.Object@70dea4e
弹栈成功,元素为:java.lang.Object@5c647e05
弹栈成功,元素为:java.lang.Object@33909752
弹栈成功,元素为:java.lang.Object@55f96302
弹栈成功,元素为:java.lang.Object@3d4eac69
弹栈成功,元素为:java.lang.Object@42a57993
弹栈失败,栈已空!
/*
- 为某个酒店编写程序:酒店管理系统,模拟订房、退房、打印所有房间状态等功能
- 1.该系统的用户是:酒店前台
- 2.酒店使用一个二维数组来模拟
- 3.酒店中的每个房间应该是一个Java对象:Room
- 4.每一个房间应该有:房间编号、房间类型、房间是否空闲
- 5.系统应该对外提供的功能:
- 可以预定房间:用户输入房间编号,订房
- 可以退房:用户输入房间编号,退房
- 可以查看所有房间的状态:用户输入某个指令应该可以查看所有房间状态
*/
package javaCoreTest;
import java.util.Scanner;
public class ArrayTest12 {
public static void main(String [] args) {
Hotel hotel = new Hotel();
/**
* 输入欢迎界面
*/
System.out.println("欢迎使用酒店管理系统,请认真阅读以下使用说明");
System.out.println("功能编号对应的功能:1表示查看房间列表,2表示订房,3表示退房,0表示退出系统");
Scanner in = new Scanner(System.in);
while(true) {
System.out.println("请输入功能编号:");
int i = in.nextInt();
if(i == 1) {
hotel.print();
}else if(i == 2){
System.out.println("请输入房间编号:");
int roomNo = in.nextInt();
hotel.order(roomNo);
}else if(i == 3) {
System.out.println("请输入房间编号:");
int roomNo = in.nextInt();
hotel.exit(roomNo);
}else if(i == 0) {
System.out.println("再见,欢迎下次再来!");
return;
}else {
System.out.println("输入功能有误,请重新输入");
}
}
}
}
class Room{
/**
* 房间编号:
* 1楼:101 102 103 104 105 106
* 2楼:201 202 203 204 205 206
* 3楼:301 302 303 304 305 306
*/
private int no;
/**
* 房间类型:标准间 单人间 总统套房
*/
private String type;
/**
* 房间状态:
* true表示空闲,房间可以被预定
* false表示占用,房间不能被预定
*/
private boolean status;
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;
}
//IDE工具对于boolean类型的变量,生成的get方法的方法名是:isXxx()
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
//重写equals方法
public boolean equals (Object obj) {
if(obj == null || !(obj instanceof Room))return false;
if(this == obj) return true;
Room room = (Room)obj;
return this.no == room.no;
}
//重写toString方法
public String toString() {
return "[" + no + "," + type + "," + (status ? "空闲" : "占用") + "]";
}
}
class Hotel{
/**
* 二维数组,模拟酒店所有房间
*/
private Room [][] rooms ;
public Hotel(){
//动态初始化
rooms = new Room[3][10];
for(int i = 0; i < rooms.length; i++) {
for(int j = 0; j < rooms[i].length; j++) {
if(i == 0) {
rooms[i][j] = new Room((i+1)*100+j+1, "单人间", true);
}
if(i == 1) {
rooms[i][j] = new Room((i+1)*100+j+1, "双人间", true);
}
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();
}
}
/**
* 订房方法:
* 调用此方法时需要传递一个房间编号。这个房间编号由前台小姐姐输入
*/
public void order(int roomNo) {
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 + "已退房");
}
}