本文共 16168 字,大约阅读时间需要 53 分钟。
一、一维数组
1、Java语言当中的数组是一种引用数据类型,数组的父类型是Object 2、数组实际上是一个容器,可以同时容纳多个元素(数组是一个数据的集合) 3、数组当中可以存储“基本数据类型”的数据 ,也可以存储“引用数据类型”的数据 4、因为数组是引用数据类型,所以数组对象存储在堆内存当中。 5、数组当中如果存储的是"java对象"的话,实际上存储的是对象的“引用(内存地址)”,数组中不能直接存储java对象 6、java中规定,数组一旦创建,其长度不可变(数组长度不可变) 7、数组的分类:一维数组、二维数组、多维数组(一维数组使用较多,二维数组偶尔使用) 8、所有的数组对象都有length属性,用来获取数组中元素的个数 9、java中的数组,要求数组中元素的类型同一,如:int类型的数组只能存储int类型的数据 10、数组中的元素内存地址是连续的(存储的每一个元素都是有规则的挨着排列的), 内存地址连续,这是数组存储元素的特点。数组实际上是一种简单的数据结构。 11、所有的数组都是拿“第一个小方块的内存地址”作为整个数组对象的内存地址(数组中首元素的内存地址作为整个数组对象的内存地址) 12、数组中每个元素都是有下标的,下标从0开始,以步长为1递增,最后一个元素的下标是:length - 1。 下标的作用:利用下标对数组的中的元素做“存取”操作 13、数组的优缺点: 优点:查询/检索/查找某个下标上的元素时效率极高。可以说是查询效率最高的一种数据结构 为什么检索效率高? 1)每一个元素的内存地址在空间存储上是连续的 2)每一个元素类型相同,所以占有空间大小一样 3)知道第一个元素的内存地址,知道每一个元素占用空间的大小,知道下标,所以 可以通过一个数学表达式计算出某个下标上元素的内存地址,直接通过内存地址定位 元素,所以数组的检索效率是最高的。 缺点: 1)由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者增加元素的时候效率极低, 因为随机增删元素会涉及到后面元素统一向前或者向后位移的操作。 2)数组不能存储大数据量 原因:很难在内存空间上找到一块特别大的连续的内存空间。 【注】对于数组中最后一个元素的增删,是没有效率影响的。 14、一维数组声明/定义: 语法格式: int[] array1; double[] array2; boolean[] array3; String[] array4; Object[] array5; 15、数组的初始化: 1)初始化数组有两种方式: 方式一:静态初始化:声明的同时赋值 语法格式: int[] array = {10,34,45,67,35} int[] array = new int[]{10,34,45,67,35} Object[] array = {new Object(),new Object(),new Object()} 方式二:动态初始化:先声明,后通过数组的下标赋值 //此处的8表示数组的大小/长度 //初始化一个长度为8的大小的String类型的数组,每个元素的默认值为null String[] array = new String[8];Object[] array = new Object[4]; //此处的10表示数组的大小/长度 //初始化一个长度为10的大小的int类型的数组,每个元素的默认值为0 int[] array = new int[10];2)静态初始化和动态初始化的使用场景: (1)当创建数组的时候,确定数组中存储哪些具体的元素时,采用静态初始化方式 (2)当创建数组的时候,不确定数组中存储哪些具体的元素时,但确定数组的大小, 采用动态初始化方式,预先分配内存空间。
16、数组越界异常(java.lang.ArrayIndexOutOfBoundsException):
访问数组的时候超过了其允许的下标的长度,就会出现数组越界异常。/** * 以下程序测试的内容 * 1、数组的静态初始化 * 2、数组的动态初始化 * 3、length方法、 * 4、利用下标对数组的元素进行“存取”操作 * 5、数组的遍历:1)普通for 2)foreach */public class ArrayTest01 { public static void main(String[] args) { //声明一个基本数据类型int类型的数组,采用静态初始化 int[] arr1 = { 1,4,5,6,7}; //声明一个引用数据类型Object类型的数组,采用静态初始化 Object obj1 = new Object(); Object obj2 = new Object(); Object obj3 = new Object(); Object[] arr2 = { obj1,obj2,obj3}; //上面四句代码可以写成如下形式 //Object[] arr2 = {new Object(),new Object(),new Object()}; //声明一个基本数据类型int类型的数组,采用动态初始化 char[] arr3 = new char[4];//char的默认值为\u0000 //声明一个引用数据类型Object类型的数组,采用动态初始化 Object[] arr4 = new Object[3]; //length属性的测试 System.out.println("数组长度: "+arr1.length); System.out.println("数组长度: "+arr4.length); //利用下标对数组的元素进行“存取”操作 arr1[arr1.length -1] = 9; arr3[0] = 'A'; arr3[2] = 'B'; //普通for循环遍历arr1 for (int i = 0; i < arr1.length ; i++) { if (i == arr1.length-1) { System.out.print("元素"+i+"==>"+arr1[i]); System.out.println(); break; } System.out.print("元素"+i+"==>"+arr1[i]+'\t'); } //普通for循环遍历arr3 for (int i = 0; i
package Test;import java.util.Random;/** * 以下程序测试的内容: * 1、提供数组的正序、倒叙遍历 * 2、随机生成数组 * 3、数组作为方法的参数 * 4、方法的可变参数和混合参数 */public class ArrayTest02 { public static void main(String[] args) { String[] arr = new String[]{ "abc","def","ghj","xyz"}; ArrTools.traversal(1,arr); ArrTools.traversal(0,arr); String[] arr1 = ArrUtil.create_Str_Arr(3,5); ArrTools.traversal(0,arr1); int[] arr2 = ArrUtil.create_Int_Arr(4,5); ArrTools.traversal(0,arr2); }}class ArrTools{ /** * 该方法用来遍历String类型的数组 * @param way 该参数用来控制遍历是正序遍历还是逆序遍历:0代表正序遍历,非0代表倒叙遍历 * @param args 该参数代表传入的参数是String类型的数组 */ public static void traversal(int way,String[] args){ if(way == 0){ for (int i = 0; i < args.length; i++) { System.out.print((i!=args.length-1)?(i+"=>"+args[i]+'\t'):(i+"=>"+args[i]+'\n')); } }else{ for (int i = args.length-1; i >=0 ; i--) { System.out.print((i != 0)?(i+"=>"+args[i]+'\t'):(i+"=>"+args[i]+'\n')); } } } /** * 该方法用来遍历int类型的数组 * @param way 该参数用来控制遍历是正序遍历还是逆序遍历:0代表正序遍历,非0代表倒叙遍历 * @param args 该参数代表传入的参数是int类型的数组 */ public static void traversal(int way,int[] args){ if(way == 0){ for (int i = 0; i < args.length; i++) { System.out.print((i!=args.length-1)?(i+"=>"+args[i]+'\t'):(i+"=>"+args[i]+'\n')); } return; } for (int i = args.length-1; i >=0 ; i--) { System.out.print((i != 0)?(i+"=>"+args[i]+'\t'):(i+"=>"+args[i]+'\n')); } } /** * 该方法用来遍历char类型的数组 * @param way 该参数用来控制遍历是正序遍历还是逆序遍历:0代表正序遍历,非0代表倒叙遍历 * @param args 该参数代表传入的参数是char类型可变参数,可变参数本质上属于数组 */ public static void traversal(int way,char... args){ if(way == 0){ for (int i = 0; i < args.length; i++) { System.out.print((i!=args.length-1)?(i+"=>"+args[i]+'\t'):(i+"=>"+args[i]+'\n')); } }else{ for (int i = args.length-1; i >=0 ; i--) { System.out.print((i != 0)?(i+"=>"+args[i]+'\t'):(i+"=>"+args[i]+'\n')); } } }}class ArrUtil{ /** * 该方法用来生成一个String[]类型的数组 * @param str_len 该参数用来控制每个元素的长度 * @param arr_size 该参数用来控制数组的长度 * @return 返回一个String类型的数组 */ public static String[] create_Str_Arr(int str_len,int arr_size) { String str = "qwertyuioplkjhgfdsamnbvcxzQWERTYUIOPLKJHGFDSAZXCVBNM"; Random rd = new Random(); String[] arr = new String[arr_size]; for (int i = 0; i < arr_size; i++) { StringBuffer sb = new StringBuffer(); for (int j = 0; j < str_len; j++) { int index = rd.nextInt(52); sb.append(str.charAt(index)); } arr[i] = sb.toString(); } return arr; } /** * 该方法用来生成一个int[]类型的数组 * @param num_len 该参数用来控制每个元素的长度 * @param arr_size 该参数用来控制数组的长度 * @return 返回一个int类型的数组 */ public static int[] create_Int_Arr(int num_len,int arr_size) { int[] arr = new int[arr_size]; Random rd = new Random(); switch (num_len){ case 1: for (int i = 0; i < arr_size; i++) { arr[i] = rd.nextInt(10); } break; case 2: for (int i = 0; i < arr_size; i++) { arr[i] = rd.nextInt(100); } break; case 3: for (int i = 0; i < arr_size; i++) { arr[i] = rd.nextInt(1000); } break; case 4: for (int i = 0; i < arr_size; i++) { arr[i] = rd.nextInt(10000); } break; } return arr; }}
package Test;/** * JVM调用main方法的时候,会自动传递一个String数组过来 */public class ArrayTest03 { //这个方法程序员负责写出来,JVM负责调用。JVM调用的时候会传递一个String数组 public static void main(String[] args) { //main方法的String数组的长度是0,因为长度为0,所以args不是null System.out.println(args.length); //main方法的String数组的长度是0,所以访问String数组的第一个元素会发生数组越界异常 System.out.println(args[0]); //main方法中传递的String数组args相当于以下的两个数组:args1、agrs2 String[] args1 = { }; String[] args2 = new String[0]; System.out.println("args1的长度:"+args1.length); System.out.println("args2的长度:"+args2.length); /* 那么main方法中的String数组args什么时候会有值呢? 其实这个数组是给用户的,用户可以在控制台上输入参数,这个参数会被自动转换为"String[] agrs" 例如在DOS窗口中用一下方式运行程序: java ArrayTest03 bgp as 100 此时JVM会自动将"bgp as 100"通过空格的方式进行分离,分离完之后自动放到"String[] agrs"数组 此时"String[] agrs"变为:String[] agrs = {"bgp","as","100"} 所以main方法中的"String[] agrs"数组主要是用来接收用户输入参数的。 例如在IDEA工具中运行程序: 1)方式一:Run右击--->Edit Configurations...--->Application--->ArrayTest03---->Programe arguments 2)方式二:ArrayTest03右击---->Edit 'ArrayTest03.main'...---->Programe arguments */ /** * 以下程序用来说明main方法中的"String[] agrs"数组的作用 * 模拟一个系统,假设要使用该系统,必须提供用户名和密码登录之后才能使用 */ if(args.length != 2){ System.out.println("使用该系统时需要输入用户名和密码信息,例如:admin 123"); } String username = args[0]; String password = args[1]; //假设用户名为:admin,密码为:Root@123,其他一律失败 /* //这样编写程序,当传进来的username和password为空时,会发生空指针异常 if (username.equals("admin") && password.equals("Root@123")){} //这样编写程序,可以避免空指针异常的出现,当传进来的username和password为空时,也不会发生空指针异常 if ("admin".equals(username) && "Root@123".equals(password)){} */ if ("admin".equals(username)&&"Root@123".equals(password)){ System.out.println("欢迎【"+username+"】使用学生系统"); }else{ System.out.println("您输入的用户名或者密码不正确,请重新输入!"); } }}
package Test;/** * 测试一维数组中存储引用数据类型 * 一维数组中存储引用数据类型:实际上存储的是java对象的"内存地址",数组中存储的每个元素是"引用" */public class ArrayTest04 { public static void main(String[] args) { Animal[] animal_arr = { new Cat(),new Bird()}; traversal(animal_arr); } public static void traversal(Animal[] animal_arr){ for (Animal ele : animal_arr) { if (ele instanceof Cat){ //如果想调用父类中存在的方法不需要向下转型,直接使用父类型的引用调用即可 ele.move(); //如果想调用子类中特有的方法需要向下转型 /* Cat cat= (Cat)ele; cat.catch_Mouse(); */ //以上两行代码可以合并成如下一行 ((Cat) ele).catch_Mouse(); }else{ ele.move(); ((Bird)ele).sing(); } } }}class Animal{ public void move(){ System.out.println("动物在移动"); }}class Cat extends Animal{ @Override public void move() { //super.move(); System.out.println("猫在走猫步"); } public void catch_Mouse(){ System.out.println("猫抓老鼠!"); }}class Bird extends Animal{ @Override public void move() { //super.move(); System.out.println("鸟儿会飞翔"); } public void sing(){ System.out.println("小鸟会唱歌"); }}
二、一维数组的扩容/缩容
1、在java语言中,数组一旦创建,其长度不可变,那么数组满了如何解决? 1)、解决方案:数组满了,需要扩容 2)、java的数组扩容原理: 先创建一个大容量数组,然后将小容量数组中的数据一个一个拷贝到大数组当中。 3)、因为扩容需要拷贝数组,所以说数组扩容的效率很低,所以在开发中提前估计好数组的长度, 尽可能少的使用数组拷贝,提高效率。 2、数组拷贝 源码: public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);package Test;public class ArrayTest05 { public static void main(String[] args) { String[] src ={ "123a","3rf","rf","rgd","moog"}; String[] dest = new String[6]; System.arraycopy(src,0,dest,1,4); for (int i = 0; i < dest.length; i++) { System.out.print((i!=dest.length-1)?(i+"=>"+dest[i]+'\t'):(i+"=>"+dest[i]+'\n')); } }}
package Test;public class ArrayTest07 { public static void main(String[] args) { //"中国"字符串也是java对象,属于String类型 //Object[] arr ={new Object(),new Student(),"中国"}; MyStack stack = new MyStack(); for (int i = 0; i <11 ; i++) { stack.push(new Product()); } for (int i = 0; i < 11 ; i++) { stack.pop(); } }}class Product{ }class Student{ }
三、二维数组
1、二维数组其实是一个特殊的一维数组,因为二维数组的每一个元素都是一个一维数组 2、三维数组是一个特殊的二维数组,因为三维数组的每一个元素都是一个二维数组 3、二维数组初始化: 动态初始化: 数据类型 数组名称[][] = new 数据类型[行的个数][列的个数]; 例如: String arr[][] = new String[3][2]; 静态初始化: 数据类型 数组名称[][] = new 数据类型[][]{ {值1,值2…},{值1…},…}; 数据类型 数组名称[][] = { {值1,值2…},{值1…},…}; int[][] arr = { {1,23,13},{54,15,6},{7,81,90}} 4、二维数组中元素的"查"和"改" 数组名称[二维数组中一维数组的下标][一维数组的元素的下标] 如: arr[2][64] 表示第三个一维数组中的第65个元素package Test;/** * 以下程序测试的内容: * 1、提供二维数组的正序、倒叙遍历 * 2、随机生成二维数组 * 3、数组作为方法的参数 */ import java.util.Random;public class ArrayTest06 { public static void main(String[] args) { //静态初始化二维数组 int[][] arr1 = { { 12,34,45,678,8,4}, { 4,5,6}, { 2}, { 23,43}, { 498,43,6,54,9} }; String[][] arr2 = new String[3][3]; arr2[0][0] = "西安"; arr2[1][1] = "南京"; arr2[2][2] = "成都"; //遍历二维数组 //正序遍历 traversal(arr2,0); //逆序遍历 traversal(arr2,1); String[][] arr3 = create_Array(2,5,4); traversal(arr3,0); } /** * 该方法用来生成一个String[][]类型的二维数组 * @param row 该参数用来控制二维数组的长度(即行) * @param line 该参数用来控制二维数组中一维数组的长度(即列) * @param str_len 该参数用来控制二维数组中一维数组的元素的大小(即列的元素的大小) * @return 该方法返回值是一个二维数组 */ public static String[][] create_Array(int row,int line,int str_len){ String str = "qwertyuioplkjhgfdsamnbvcxzQWERTYUIOPLKJHGFDSAZXCVBNM"; Random rd = new Random(); String[][] arr = new String[row][line]; for (int i = 0; i < row ; i++) { for (int j = 0; j < line; j++) { StringBuffer sb = new StringBuffer(); for (int m = 0; m < str_len; m++) { int index = rd.nextInt(52); sb.append(str.charAt(index)); } arr[i][j] = sb.toString(); } } return arr; } /** * 该方法用来遍历二维数组 * @param args 该参数代表传入的实参为一个二维数组 * @param way 该参数代表传入的实参为一个int类型的数字,用来控制正序遍历和逆序遍历 */ public static void traversal(String[][] args,int way){ if(0 == way){ for (int i = 0; i < args.length ; i++) { for (int j = 0; j < args[i].length; j++) { System.out.print((j != args[i].length-1)?(args[i][j]+'\t'):(args[i][j]+'\n')); } } return; }else{ for (int i = args.length-1; i >= 0 ; i--) { for (int j = args[i].length-1; j >=0; j--) { System.out.print((j != 0)?(args[i][j]+'\t'):(args[i][j]+'\n')); } } } }}
【模拟栈数据结构练习】 package Test;import java.util.Arrays;/** * 编写程序:使用一维数组,模拟栈数据结构 * 要求: * 1、这个栈可以存储java中的任何引用数据类型的数据 * 2、在栈中提供push方法模拟压栈(栈满了,提示信息:压栈失败) * 3、在栈中提供pop方法模拟弹栈(栈空了,提示信息:弹栈失败) * 4、编写测试程序,new对象,调用push、pop方法来模拟压栈弹栈的动作 * 5、假设栈的初始化容量是10(注意无参构造方法的编写方式) */public class MyStack { //栈类 //提供一个数组来存储栈中的元素 //为什么使用Object类型的数组?因为这个栈可以存储java中的任何引用数据类型的数组 Object[] elements;//= new Object[10]; //栈帧,永远指向栈顶元素 //因为最初的栈是空的,一个元素都没有,所以栈帧的初始值应该为0 //private int index = 0;//如果index采用0,表示栈帧指向了顶部元素的上方 //private int index = -1;//如果index采用-1,表示栈帧指向了顶部元素 private int index; public MyStack() { //动态初始化一个一维数组,默认初始化容量是10 this.elements = new Object[10]; //index初始化 index = -1; } /** * 该方法为压栈的方法 * @param obj 被压入的元素 */ public void push(Object obj){ if(this.index >= this.elements.length-1){ System.out.println("栈已满,压栈失败"); return; } this.index++; this.elements[index] = obj; //以上两句代码可以合成下面一句 //this.elements[++index] = obj; System.out.println("压栈"+obj+"元素成功,栈帧指向:" + index); } /** * 该方法为弹栈的方法,从数组中往外取元素,每取出一个元素,栈帧向下移动一位。 */ public void pop(){ if(index < 0){ System.out.println("弹栈失败,栈已空"); return; } System.out.print("弹栈"+elements[index]+"元素成功" + index+'\t'); index--; System.out.println("栈帧指向:"+index); } public Object[] getElements() { return elements; } public void setElements(Object[] elements) { this.elements = elements; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MyStack myStack = (MyStack) o; return Arrays.equals(elements, myStack.elements); } @Override public int hashCode() { return Arrays.hashCode(elements); }}
转载地址:http://sljv.baihongyu.com/