unit8
Unit8 数组
1. 理解数组
2. 一位数组
3. 二维数组
4. 多维数组
1、认识数组
软件的基本功能是处理数据,而在处理数据时,必须先进行数据持有,将数据持有之后,再对数据进行处理。我们将程序中可以临时存储数据的部分叫做容器。
在java中,存储数据的容器效率最快的就是数组,也是java最基本的容器。
数组,顾名思义就是一组数据,物以类聚,人以群分,当然这一组数据所有成员应该是同一类型的,才变得有意义。
数组不是基本数据类型,是引用数据类型(稍后解释),它可以用来存放数据。这存放的数据既可以是基本数据类型,也可以是引用数据类型,一句话说,数组就是同一种类型数据的集合,通过数组的索引方便的操作集合中的数据。
a) 数组简介
Java当中具有持有数据功能的容器中,数组是最基本的。
l 数组特点
• 数组是Java当中效率最快的容器
• 数组的长度是固定的
• 数组中只能存储一种类型的数据
l 数组的定义
与基本类型不同,数组数据引用数据类型,需要创建实例
格式:
数据类型[] 数组名 = new 数据类型[数组长度] ;
示例:int[] arr =new int[5];
还有其他格式如下:
int[] arr = newint[]{20,5,100,30,5}
int[] arr ={20,5,100,30,5}
int arr[] = newint[4];//定义时指定了数组长度
l 数组的使用
数组底层是依次将数据进行编号后直接通过编号访问(线性序列)的。这个编号叫做索引。索引从0开始计数。
这里的”访问”包含以下两个动作:获取值与赋值
直接打印数组名是获取了数组的地址
访问数组中指定编号的元素:数组名[索引]
l 数组使用注意事项
在使用数组时,因为不当的操作,我们可能会通过编译,但是在运行期间遇到一些程序报错
类似这样编译时不报错,运行期报错的错误叫运行时错误
数组最常见的两个运行时错误:
• 空指针异常
编程语言中对空的处理与我们平常所理解的略有不同。这里我们区分两种空的不同
变量完全没有值:
定义了变量根本没有值:int a; int[] b
这样根本没有赋值过的变量是无法使用的。数组也是一种数据类型,可以指定变量,没有赋值是不能使用的。
int[] arr;
System.out.println(arr.length);
变量有值,但值为null:
定义了变量并且赋值了,但是值是空值,是常量。这种情况只针对于引用数据类型,基本数据类型不成立。
int a = null; 编译失败
int[] arr =null; 正常赋值
当使用int[] arr =null给arr赋值时,变量arr作为数组名通过编号访问数组元素时编译不报错,运行时报运行错误NullPointerException空指针异常
int[] arr3 = null;
System.out.println(arr3);//打印结果为空,自然无法使用该数组
System.out.println(arr3[0]);
• 数组索引越界异常
当数组中不存在该索引却访问该索引时,运行时报错:
ArrayIndexOutOfBoundsException 数组索引越界
System.out.println(arr2[6]);//会报数组角标越界异常,因为arr2没有第7个数
引用数据类型与基本数据类型存储时,存储的方式并不相同。引用数据类型是更为常见的数据类型,基本数据类型是为了便于开发预定好的特殊数据类型。这里我们将讨论引用数据类型的内存存储原理。
l 内存分区
内存是计算机临时存储数据的区域,我们会将内存在逻辑上分配成不同区域方便对数据进行分类高效管理。
• 寄存器:最快的存储区域直接与cpu打交道,是程序员无法控制的计算区域,简单的理解,就是记录下当前java字节码文件执行到了第几行,下次cpu执行到java程序的时候,接着执行。
• 堆栈:又叫栈,仅次于寄存器。用于存储局部变量。
• 堆:通用内存池,用于存放所有引用数据类型对象。每个对象均有地址,且有默认初始化值,java程序执行中,遇到使用new关键字创建的引用数据类型,都是存放在堆空间。
• 方法区:用于存放永远不会被改变的值,如类信息,静态成员。
• 诸如硬盘形式的永久存储区域。
l 数组是引用数据类型
了解内存结构将有助于后期整个面向对象的学习。
int[] arr = newint[]{1,5,6,1,7};
• 引用变量:引用数据类型定义的变量(arr)存储在栈内存当中,这个arr变量叫做这个数组实例的引用变量。
• =:与数学当中的意义不同,是赋值的意思,并非相等。
• 真正的数组实例是通过new关键字创建出来,存储于堆内存中,并产生一个十六进制表示的内存地址0x1A29。
• 在数组创建期间,会将所有值默认初始化,再进行赋值。对于int型的数值,其默认值为0。
• 这个引用变量会指向这个数组的内存地址
换句话说:引用变量的值是这个数组实例的地址值
再换句话说:引用变量通过地址可以表示这个数组对象
c) 数组中元素的默认值
定义一个类型的数组,一开始只是指定了数组的长度,并没有说明里面存的数据的值是多少,那么,虚拟机会给这些数据一个默认值。
byte[] arrByte = new byte[3];
short[] arrShort = new short[3];
int[] arrInt =new int[3];
long[] arrLong = new long[3];
boolean[] arrBoolean = new boolean[3];
char[] arrChar = new char[3];
float[] arrFloat = new float[3];
double[] arrDouble = new double[3];
String[] arrStrings = new String[3];
System.out.println("byte类型数组中的数据默认值是:"+arrByte[1]);
System.out.println("short类型数组中的数据默认值是:"+arrShort[1]);
System.out.println("int类型数组中的数据默认值是:"+arrInt[1]);
System.out.println("long类型数组中的数据默认值是:"+arrLong[1]);
System.out.println("boolean类型数组中的数据默认值是:"+arrBoolean[1]+0);
System.out.println("char类型数组中的数据默认值是:"+arrChar[1]);
System.out.println("float类型数组中的数据默认值是:"+arrFloat[1]);
System.out.println("double类型数组中的数据默认值是:"+arrDouble[1]);
System.out.println("String类型数组中的数据默认值是:"+arrStrings[1]);
执行结果为:
byte类型数组中的数据默认值是:0
short类型数组中的数据默认值是:0
int类型数组中的数据默认值是:0
long类型数组中的数据默认值是:0
boolean类型数组中的数据默认值是:false0
char类型数组中的数据默认值是:_
2、一维数组
数组中可以定义成千上万个数据,使用从0~n来表示这些数据的索引,就是一维数组
数组的定义:
//静态初始化
int[] arr2 = {1,2,3,4,5};
//初始化
int[] arr3 = new int[3];
数组的访问:
//数组的使用,通过索引来对数组中的数据进行操作
System.out.println(arr2[2]);//获取数组arr2中第三位数据并打印出来。
这里使用两个案例来对一维数组进行练习:
1、 遍历打印数组
2、 将一维数组倒序排列(同时讲解内存中的变化)
3、二维数组
二维数组提供了更方便的存储方式,帮助我们实现更为复杂的业务。也就是说,一维数组里面的元素也是一维数组。
定义一个二维数组
int[][] intArr = new int[2][2];
//开始为intArr数组进行赋值操作
intArr[0][0] = 1;
intArr[0][1] = 2;
intArr[1][0] = 3;
intArr[1][1]= 4;
赋值的过程:给第intArr数组中第1个数组中第1个元素赋值为1,给第intArr数组中第1个数组中第2个元素赋值为2,给第intArr数组中第2个数组中第1个元素赋值为3,给第intArr数组中第2个数组中第2个元素赋值为4.
既然是数组成员还是数组,那么,第二级的数组的长度是不是也可以和别的一级成员下的数组长度不一样呢?
如:intArr[0]是intArr数组中第1个元素,而这个元素还是一个数组,:intArr[1]是intArr数组中第2个元素,这个元素也是一个数组,那么intArr[0]和intArr[1]都是数组,他们的数组长度可以不一样,因为他们之间的成员并没有任何联系,只要他们两个数据的类型是数组类型就可以了,当然,他们的成员得和声明数组时指定的数据类型一致!
//定义一个第二级长度不一的二维数组
int[][]intArr2 = new int[3][];//第一个中括号中必须指定第一级的长度,第二个中括号中可以不指定长度,在之后可以通过别的方式定义二维数组。
intArr2[0] = new int[3];
intArr2[1] = new int[4];
intArr2[2]= new int[5];
System.out.println("打印各个二级数组的长度");
System.out.println(intArr2[0].length);
System.out.println(intArr2[1].length);
System.out.println(intArr2[2].length);
数组都是可以声明静态初始化,那么看一下二维数组的静态初始化。
1、 静态初始化一级、二级数组的数据。
//静态初始化二级数组
int[][] intArr3 = {{1,2,3,4},{5,6,7},{8,9,10,11,12,13}};
//使用for循环打印一下二维数组的长度
for (int i = 0; i < intArr3.length; i++) {
System.out.println(intArr3[i].length);
}
2、 先定义一级数组范围,再静态初始化一个数组,赋值给二级数组
//先初始化数组,再将一个静态初始化的数组赋值给这个二级数组
int[][] intArr4 = new int[3][];
intArr4[0] = new int[]{1,2,3};
intArr4[1] = new int[]{4,5,6,7,8};
intArr4[2] = new int[]{8,9};
案例:对二级数组进行遍历打印。
99乘法表的打印
3、 多维数组
当我们的业务需要更多维数的数组时,可以再多加[]定义。
//定义一个三维数组
int[][][] intArr5= new int[3][][];
案例:使用Random工具类对三维数组进行随机赋值。
使用二维数组存储个人信息
数组练习:
冒泡排序:
class MaoPao
{
public static void main(String[] args){
int[] arr = {11,0,1,1,2,5,3,7,4,8,14,19};
//将最大值挪到最左边
for(int i = 1 ; i <arr.length ; i++){
if(arr[0] < arr[i]){
int temp = arr[0];
arr[0] = arr[i];
arr[i] =temp;
}
}
System.out.println("将最大值挪到最左边:"+arr[0]);
/*
拿起始的数字和后面的数字挨个比较
如果比后面的数字小,那就换个位置
第一层循环定义j,第二层循环i为后面数字
的角标,在内层循环中,arr[j]是一个固定值
拿这个固定值挨个和后面的数字相比,将
最小的换到最左边。
第一次外层循环:j=0
进入内层循环,拿arr[j]和后面每一位数字
arr[i]相比,内层循环中,arr[i]是从arr[j]后面的
一位数开始,也就是i=j+1
在内层循环中,当arr[j]小于arr[i],说明
arr[j]这位数字不是最大数,所以和当前循环
arr[i]的这位数字换个位置。
假如j是从0开始,那么就是说,拿arr[0]和
arr[0]后面的每一位数字相比,直到将arr[0]和
后面数字比完,结束内层循环,这个时候结果
就是将最大数留给了 arr[0]。
当再次开始外层循环,那就不能从arr[0]开始了
因为,arr[0]在这个时候已经是最大数,再次
进入循环当然是没有意义的,应该是将剩下的
数字中,最大的数字排到arr[1],所以在第二次
外层循环,应该是从arr[1]开始,就是arr[j]
再拿arr[1]也就是arr[j]位上的数去和他们后面
的每一个数字相比,如果出现arr[1]位上的数
比后面的某一位小,就说明arr[1]当前的数字
还不是最大值,再将较大的值给了arr[1],当
结束了这次内循环后,arr[1]的值就是arr[1]到
他后面的数字最大的数!
然后重复外层循环……
直到j小于数组的角标-1,因为j是和他后面的
一位数字相比,就不能等于角标,否则会
出现角标越界
如:长度为10,那么角标最大为9,j的最大值
是9,当进入内层循环,arr[9+1]是不存在的,
arr[9]已经是最后一位了,没有比较的了,
所以应该外层循环在倒数第二位的时候,也
就是length-1的位置结束。
*/
for(int j = 0 ; j <arr.length - 1; j++){
for(int i = j +1; i <arr.length; i++){
if(arr[j] < arr[i]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] =temp;
}
}
}
//System.out.println(arr[arr.length-1]);
for(int i:arr){
System.out.println(i);
}
}
}
更简单的一个冒泡算法:
class Test
{
//更简单的一个冒泡排序
public static void main(String[] args){
int[] arr = {2,1,3,44,11,22,14,55};
/*
每次内层循环,将本次循环对应的数组中
的数,和他前面的数比较一下,如果前面的数
比后面的数小,那就把他们两个换个位置
这样,内层循环结束后,最小的数,就被
挪到了最右边。
然后进行arr.length次外层循环,再对剩下的数
进行排序,这个时候,内层循环就没有必要
比较最后一个数了,因为前面的内层循环就将
最小的数挪到了最右边,所以没必要比较。
所以,内层循环的次数可以缩减,缩减的标记
就是外层循环的i
*/
for(int i = 0 ; i <arr.length; i++){
for(int j = 1; j < arr.length - i ; j++){
if(arr[j-1] < arr[j]){
int temp = arr[j-1];
arr[j-1]= arr[j];
arr[j] = temp;
}
}
}
for(int x : arr){
System.out.println(x);
}
for(int i = 1 ; i <=9 ; i ++){
for(int j = 1 ; j <= i ; j ++){
System.out.print(j + "*" +i + " = " + i * j + " ");
}
System.out.println();
}
}
}
双列数组存储键值对应数据:
import java.util.scanner;
//使用双列数组存储用户信息
class ShuangLie
{
static String[] nameArr = new String[10];
static int tag = 0 ;
static String[] passwordArr = new String[10];
public static void main(String[] args){
System.out.println("请问您要执行什么操作!");
//1:存储账号密码
//2:找回密码
//3:登录
Scanner sc = new Scanner(System.in);
while(true){
System.out.println("1:新增账号密码");
System.out.println("2:找回密码");
System.out.println("3:登录");
System.out.println("4:结束系统");
int choose = sc.nextint();
switch(choose){
case 1:
System.out.println("请输入账号");
String newUserName = sc.next();
System.out.println("请输入密码");
String newPassword = sc.next();
boolean boo1 = newUser(newUserName,newPassword);
if(boo1){
System.out.println("新增成功");
}else
System.out.println("新增失败");
break;
case 2:
System.out.println("请输入账号");
String getUserName = sc.next();
String result = getPassword(getUserName);
System.out.println("找回密码结果为:"+result);
break;
case 3:
System.out.println("请输入账号");
String userName = sc.next();
System.out.println("请输入密码");
String password = sc.next();
boolean boo2 = login(userName,password);
if(boo2){
System.out.println("登录成功");
}else
System.out.println("登录失败");
break;
case 4:
System.out.println("结束系统");
return;
default:
System.out.println("您输入的选择错误,请重新输入");
}
System.out.println("\n----------这是一个漂亮的分隔符--------------\n");
}
}
public static boolean newUser(String name,String password){
nameArr[tag] = name;
passwordArr[tag] = password;
tag++;
return true;
}
public static String getPassword(String name){
for(int i = 0 ; i < tag ;i++){
if(nameArr[i].equals(name)){
return passwordArr[i] ;
}
}
return "查询失败";
}
public static boolean login(String userName,String password){
for(int i = 0 ; i < tag ;i++){
if(nameArr[i].equals(userName)){
if(passwordArr[i].equals(password)){
return true;
}
}
}
return false;
}
}
数组练习:
package day08;
public class ShuZu {
public static void main(String[] args) {
//数组:同一种数据类型数据的集合,定义数组时必须指定数组的长度。
//数组的定义方式,初始化和静态初始化。
//初始化:定义时,指定数据类型和数组长度,虚拟机为数组自动分配初始值。
int[] arr0 = new int[10];//定义了一个长度为10的int类型数组,在这里,arr0的类型是什么?
//另一种写法
int arr1[] = new int[10];//这是另一种写法,推荐第一种,语义更明确。
//静态初始化:即定义时就列出了数组中的数据
int[] arr2 = {1,2,3,4,5};
//数组的使用,通过索引来对数组中的数据进行操作
System.out.println(arr2[2]);//获取数组arr2中第三位数据并打印出来。
arr2[2] = arr1[0];//这里将arr1数组中第一个数据赋值给arr2数组中第三个数据。
// System.out.println(arr2[2]);
//数组常见的异常
//没赋值,空指针异常,就是说没有给数组的变量赋值
//int[] arr;
//System.out.println(arr.length);
//null,空指针异常,就是说定义的时候,给了一个null值,并没有给出一个真正的数组,使用的时候当然会报错
int[] arr3 = null;
// System.out.println(arr3);//打印结果为空,自然无法使用该数组
// System.out.println(arr3[0]);
// System.out.println(arr2[6]);//会报数组角标越界异常,因为arr2没有第7个数
//默认值
/*byte[] arrByte = new byte[3];
short[] arrShort = new short[3];
int[] arrInt =new int[3];
long[] arrLong = new long[3];
boolean[] arrBoolean = new boolean[3];
char[] arrChar = new char[3];
float[] arrFloat = new float[3];
double[] arrDouble = new double[3];
String[] arrStrings = new String[3];
System.out.println("byte类型数组中的数据默认值是:"+arrByte[1]);
System.out.println("short类型数组中的数据默认值是:"+arrShort[1]);
System.out.println("int类型数组中的数据默认值是:"+arrInt[1]);
System.out.println("long类型数组中的数据默认值是:"+arrLong[1]);
System.out.println("boolean类型数组中的数据默认值是:"+arrBoolean[1]+0);
System.out.println("char类型数组中的数据默认值是:"+arrChar[1]);
System.out.println("float类型数组中的数据默认值是:"+arrFloat[1]);
System.out.println("double类型数组中的数据默认值是:"+arrDouble[1]);
System.out.println("String类型数组中的数据默认值是:"+arrStrings[1]);
*/
//二维数组的初始化
int[][] intArr = new int[2][2];
//首先看一下它的长度
System.out.println(intArr.length);
//开始为intArr数组进行赋值操作
intArr[0][0] = 1;
intArr[0][1] = 2;
intArr[1][0] = 3;
intArr[1][1] = 4;
//定义一个第二级长度不一的二维数组
int[][]intArr2 = new int[3][];//第一个中括号中必须指定第一级的长度,第二个中括号中可以不指定长度,在之后可以通过别的方式定义二维数组。
intArr2[0] = new int[3];
intArr2[1] = new int[4];
intArr2[2] = new int[5];
System.out.println("打印各个二级数组的长度");
System.out.println(intArr2[0].length);
System.out.println(intArr2[1].length);
System.out.println(intArr2[2].length);
//分析一下,二维数组其实就是一维数组里面再装一个一维数组
//静态初始化二级数组
int[][] intArr3 = {{1,2,3,4},{5,6,7},{8,9,10,11,12,13}};
//使用for循环打印一下二维数组的长度
for (int i = 0; i < intArr3.length; i++) {
System.out.println(intArr3[i].length);
}
//先初始化数组,再将一个静态初始化的数组赋值给这个二级数组
int[][] intArr4 = new int[3][];
intArr4[0] = new int[]{1,2,3};
intArr4[1] = new int[]{4,5,6,7,8};
intArr4[2] = new int[]{8,9};
//定义一个三维数组
int intArr5[][][] = new int[3][][];
}
}
相关阅读
.NET 控件集 ComponentOne 2018V2正式发布,提供轻量级
ComponentOne Enterprise 是一款专注于企业应用 .NET开发的 Visual Studio 组件集,包含 300多种 .NET控件,支持 WinForm,WPF,UWP,ASP.
2018年11月8日,由中共西安市委、西安市人民政府主办的硬科技产业盛会—— “2018全球硬科技创新暨‘一带一路
720P是1280*720=921600,即分辨率为921600,即大约92万像素,921600接近100万像素(1280是按照16:9算出来的,4:3的另算,后续都按照16:9来算)
AMD FX-8320处理器怎么样 AMD FX8320配什么主板
今天在百度搜索了一下6000元FX-8320处理器规格参数是,发现其中不少网友对于AMD FX8320配什么主板都不怎么了解,不少百度知道或者论
前言 Android O的版本对RIL的框架的通信功能进行了改动,不在使用sockect进行通讯,而改用HIDL进行通信,这里结合7.0和8.0的源码,分析