JavaSE进阶16 - 数组

数组基本知识点及数组的静态初始化

package com.bjpowernode.javase.array;

/**
Array:

	1、Java语言中的数组是一种引用数据类型,不属于基本数据类型。数组的父类是Object。
	
	2、数组实际上是一个容器,可以同时容纳多个元素。(数组是一个数据的集合。)
	
	3、数组当中可以存储"基本数据类型"的数据,也可以存储"引用数据类型"的数据。
	
	4、数组因为是引用类型,所以数组对象在堆内存当中。(数组是存储在堆当中的。)
	
	5、数组当中如果存储的是"java对象"的话,实际上存储的是对象的"引用(内存地址)",数组中不能直接存储java对象。
	
	6、数组一旦创建,在java中规定,长度不可变。(数组长度不可变)
	
	7、数组的分类:一维数组、二维数组、三维数组、多维数组....(一维数组较多,二维数组偶尔使用!)
	
	8、所有的数组对象都有length属性(java自带的),用来获取数组中元素的个数。
	
	9、java中的数组要求数组中元素的类型统一。比如int类型数组只能存储int类型,Person类型数组只能存储Person类型。
	例如:超市购物,购物袋中只能装苹果,不能同时装苹果和橘子。
	
	10、数组在内存方面存储的时候,数组中的元素内存地址是连续的。内存地址连续。
	这是数组存储元素的特点。数组实际上是一种简单的数据结构。
	
	11、所有的数组都是拿"第一个小方框的内存地址"作为整个数组对象的内存地址。
	(数组中首元素的内存地址作为整个数组对象的内存地址。)
	
	12、数组中的每一个元素都是有下标的,下标从0开始,以1递增,最后一个元素的下标是:length-1。
	下标非常重要,因为我们对数组中元素进行“存取”时候,都需要通过下标来进行。
	
	13、数组这种数据结构的优点和缺点是什么?
		优点:查询/查找/检索某个下标上的元素时效率最高。可以说是查询效率最高的一个数据结构。
			为什么检索效率最高?
				第一:每一个元素的内存地址在空间存储上是连续的。
				第二:每一个元素类型相同,所以占用空间大小一样。
				第三:知道第一个元素内存地址,知道每一个元素占用空间的大小,又知道下标,所以
				通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位
				元素,所以数组的检索效率是最高的。
				
				数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,
				因为数组中元素查找的时候不会一个一个找,是通过数学表达式计算出来的。(算出一个
				内存地址,直接定位的。)
		缺点:
			第一:由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者增加元素的时候,
		效率较低,因为随机增删元素会涉及到后面元素统一向前或者向后位移的操作。
			第二:数组不能存储大数据量,为什么?
				因为很难在内存空间上找到一块特别大的连续的内存空间。
				
		注意:对于数组中最后一个元素的增删,是没有效率影响的。
		
	14、怎么声明/定义一个一维数组?
		语法格式:
			int[] array1;
			double[] array2;
			boolean[] array3;
			String[] array4;
			Object[] array5;
	
	15、怎么初始化一个一维数组呢?
		包括两种方式:静态初始化一维数组,动态初始化一维数组。
		静态初始化语法格式:
			int[] array = {100,2100,300,50};
		动态初始化语法格式:
			int[] array = new int[5];// 这里的5表示数组的元素个数
									 // 初始化5个长度的int类型数组,每个元素默认值0
			String[] names = new String[6];// 初始化6个长度的String类型数组,每个元素默认值null;
			
 */
public class ArrayTest01 {

	public static void main(String[] args) {
		// 声明一个int类型的数组,使用静态初始化的方式
		int[] a = {1,100,20,10,55,689};
		// 这是C++格式,不建议在java中使用。
		//int a[] = {1,100,20,10,55,689};
		
		// 所有的数组对象都有length属性
		System.out.println("数组中元素的个数" + a.length);
		
		// 数组中每一个元素都有下标
		// 通过下标对数组中的元素进行存和取
		// 取
		System.out.println("第一个元素 = " + a[0]);
		System.out.println("最后一个元素 = " + a[5]);
		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]);
		System.out.println("最后一个元素 = " + a[a.length-1]);	
		
		// 一维数组怎么遍历呢?
		for(int i = 0; i < a.length; i ++) {
			System.out.println(a[i]);//i是从0到5,是下标
		}
		
		// java.lang.ArrayIndexOutOfBoundsException(数组下标越界异常)
		// System.out.println(a[6]);
		
		//从最后一个元素遍历到第一个元素
		for(int i = a.length-1; i >= 0; i--) {
			System.out.println(a[i]);
		}
	}

}
  • 数组内存图
    在这里插入图片描述

数组的动态初始化

package com.bjpowernode.javase.array;

/**
关于每个类型的默认值还有印象吗?
	数据类型             默认值
------------------------------
    byte         0
    short        0
    int          0
    long         0L
    float        0.0F
    double       0.0
    boolean      false
    char         \u0000
        引用数据类型        null
        
什么时候采用静态初始化方式,什么时候使用动态初始化方式呢?
	当你创建数组的时候,确定数组中存储哪些具体的元素时,采用静态初始化方式。
	当你创建数组的时候,不确定将来数组中存储哪些数据,你可以采用动态初始化的方式,预先分配内存空间。

 */
public class ArrayTest02 {

	public static void main(String[] args) {
		// 声明一个int类型的数组,使用动态初始化的方式
		int[] a = new int[4];//创建长度为4的int数组,数组中每个元素的默认值是0
		
		// 遍历数组
		for(int i = 0;i < a.length;i ++) {
			System.out.println("数组中下标为" + i + "的元素是" + a[i]);
		}
		
		//后期赋值
//		a[0] = 0;
//		a[1] = 100;
//		a[2] = 200;
//		a[3] = 300;
		
		// 初始化一个Object类型的数组,采用动态初始化的方式
		Object[] objs = new Object[3]; // 3个长度,动态初始化,所以每个元素默认值是null;
		for(int i = 0;i < objs.length;i ++) {
			System.out.println(objs[i]);
		}
		
		// 存储Object,采用静态初始化呢?
		/*
		Object o1 = new Object();
		Object o2 = new Object();
		Object o3 = new Object();
		Object[] objects = {o1,o2,o3};
		*/
		Object[] objects = {new Object(),new Object(),new Object()};
		for(int i = 0;i < objs.length;i ++) {
			System.out.println(objects[i]);//java.lang.Object@15db9742
		}
	}

}

方法的参数是数组

package com.bjpowernode.javase.array;

// 方法的参数是数组
public class ArrayTest03 {
	
	// main方法的编写方式,还可以采用C++的语法格式哦!
	public static void main(String args[]) {
		System.out.println("hello world!");
		
		// 调用方式时,传递一个数组
		int[] x = {1,2,3,4};
		printArray(x);
		
		String[] strs = {"abc","ade","123"};
		printArray(strs);
	}	
	
	public static void printArray(int[] array) {
		for(int i = 0;i < array.length;i ++) {
			System.out.println(array[i]);
		}
	}
	
	public static void printArray(String[] strs) {
		for(int i = 0;i < strs.length;i ++) {
			System.out.println(strs[i]);
		}
	}
}

package com.bjpowernode.javase.array;

// 当一个方法的参数是一个数组的时候,我们还可以采用这种方式传递。
public class ArrayTest04 {

	public static void main(String[] args) {
		// 静态初始化一维数组
		int[] a1 = {1,2,3};
		printArray(a1);
		
		System.out.println("-------------------");
		// 没有这种语法
		//printArray({1,2,3});
		// 如果直接传递进一个静态数组,语法必须这样写
		printArray(new int[] {1,2,3});
		
		// 动态初始化一维数组
		int[] a2 = new int[4];
		System.out.println("-------------------");
		printArray(a2);
		
		System.out.println("-------------------");
		// 如果直接传递进一个动态数组,语法必须这样写
		printArray(new int[3]);// 可以运行
	}
	
	public static void printArray(int[] array) {
		for(int i = 0;i < array.length;i ++) {
			System.out.println(array[i]);
		}
	}
}

main方法String参数

package com.bjpowernode.javase.array;

/**
	1、main方法上面的"String[] args"有什么用?
		分析一下:谁负责调用main方法 --> JVM
		JVM调用main方法的时候,会自动传一个String数组过来。
		
 */
public class ArrayTest05 {
	
	// 这个方法程序员负责写出来,JVM负责调用。JVM调用的时候一定会传一个String数组过来。
	public static void main(String[] args) {
		
		// JVM默认传递过来的这个数组对象的长度?默认0
		// 通过测试得出:args不是null,否则会出现null.length,出现空指针异常。
		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"数组中
		// 所以main方法上面的String[] args数组主要是用来接收用户输入参数的。
		// 把abc def xyz转换成字符串数组:{"abc","def","xyz"}
		
		// 遍历数组
		System.out.println("-------------------");
		for(int i = 0;i < args.length;i ++) {
			System.out.println(args[i]);
		}
	}
	
	public static void printLength(String[] args) {
		System.out.println(args.length);
	}

}

eclipse中类似DOS命令窗口,在控制台输入参数,路径如下:

Run --> Run Configurations  -->  选中主class文件 --> Arguments --> Program arguments(注意以空格间隔)
  • 探究main方法中String参数的案例
package com.bjpowernode.javase.array;

// 模拟一个系统,假设这个系统要使用,必须输入用户名和密码。
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")) {
		// 这样写避免空指针异常。
		if("admin".equals(username) && "123".equals(password)) {
			System.out.println("登录成功,欢迎[" + username + "]回来");
			System.out.println("你可以继续使用该系统......");
		}else {
			System.out.println("验证失败,用户名不存在或者密码错误!");
		}
	}
}

数组扩容及数组拷贝

package com.bjpowernode.javase.array;

/**
关于一维数组的扩容:
	在java开发中,数组长度一旦确定不变,那么数组满了怎么办?
		数组满了,需要扩容。
		java中对数组的扩容是:
			先新建一个大容量的数组,然后将小容量数组中的数据一个一个拷贝到大数组当中。
			
结论:数组扩容效率较低,因为涉及到拷贝的问题,所以在以后的开发中请注意:尽可能少的进行数组的拷贝。
所以在创建数组对象的时候预估一下多长合适,最好预估准确,这样可以减少数组的扩容次数。提高效率。
	
 */
public class ArrayTest08 {

	public static void main(String[] args) {
		// java中的数组怎么进行拷贝的呢?
		//System.arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);
		// (拷贝源,拷贝源的起始下标位置,拷贝目标,拷贝目标的起始下标位置,拷贝长度)
		
		// 拷贝源(从这个数组中拷贝)
		int[] src = {1,11,22,33,44};
		
		// 拷贝目标(拷贝到这个目标数组中)
		int[] dest = new int[20];// 动态初始化一个长度为20的int类型数组,每个元素的默认值为0
		
		System.arraycopy(src, 1, dest, 3, 2);
		
		for(int i = 0; i < dest.length; i ++) {
			System.out.print(dest[i]);
			System.out.print(" ");
		}
		System.out.println();
		
		// 数组中如果存储的是引用数据类型,可以拷贝吗?当然可以。
		String[] strs1 = {"abc", "def", "xyz", "hello"};
		String[] strs2 = new String[20];
		System.arraycopy(strs1, 0, strs2, 0, strs1.length);// 将strs1的数组全被拷贝到strs2数组中
		for(int i = 0; i < strs2.length; i ++) {
			System.out.print(strs2[i]);
			System.out.print(" ");
		}
		System.out.println();
		
		Object[] objs1 = {new Object(), new Object(), new Object()};
		Object[] objs2 = new Object[10];
		// 思考一下:这里拷贝的时候是拷贝对象,还是拷贝对象的地址。(地址)
		System.arraycopy(objs1, 0, objs2, 0, objs1.length);
		for(int i = 0; i < objs2.length; i ++) {
			System.out.print(objs2[i]);
			System.out.print(" ");
		}
		
 	}
}

  • 数组拷贝-基本数据类型-内存图
    在这里插入图片描述
  • 数组拷贝-引用数据类型-内存图
    在这里插入图片描述

二维数组

  • 二维数组初了解和二维数组的length属性
package com.bjpowernode.javase.array;

/**
关于java中的二维数组
	1、二维数组其实是一个特殊的一维数组,特殊在一维数组当中的每一个元素就是一个一维数组。
	2、三维数组是一个特殊的二维数组。特殊在二维数组中的每一个元素就是一维数组。
		实际开发中使用最多的是一维数组,二维数组很少使用,三维数组几乎不用。
	3、二维数组静态初始化
		int[][] array = {{0,1},{3,4},{5,6,7}};
	


 */
public class ArrayTest09 {

	public static void main(String[] args) {
		
		// 一维数组
		int[] arr1 = {100, 200, 300};
		System.out.println(arr1.length);//3
		
		// 二维数组
		// 以下代码里面是3个一维数组
		int[][] arr2 = {
				{0, 1, 2},
				{3, 4},
				{5, 6, 7, 8},
				{9, 10, 11, 12, 13}
		};
		System.out.println(arr2.length);//4
		System.out.println(arr2[0].length);//3
		System.out.println(arr2[1].length);//2
		System.out.println(arr2[2].length);//4
		System.out.println(arr2[3].length);//5
	}

}

  • 二维数组的读和改
package com.bjpowernode.javase.array;

/*
关于二维数组的读和改
	a[二维数组中一维数组的下标][一维数组中元素的下标]
	a[0][0] 二维数组中的第1个一维数组中的第1个元素
	a[1][1] 二维数组中的2个一维数组中的第2个元素

*/
public class ArrayTest10 {

	public static void main(String[] args) {
		// 二维数组
		int[][] a = {
				{1,2},
				{3,4,5},
				{6,7,8,9}
		};
		
		// 请取出以上二维数组中的第1个一维数组
		int[] a0 = a[0];
		for(int i = 0; i < a0.length; i ++) {
			System.out.println(a0[i]);
		}
		
		// 请取出以上二维数组中的第1个一维数组中的第1个元素
		System.out.println(a[0][0]);//1
		
		// 请取出以上二维数组中的2个一维数组中的第3个元素
		System.out.println(a[1][2]);//5
		
		// 注意:越界异常 java.lang.ArrayIndexOutOfBoundsException
		System.out.println(a[2][4]);
	}

}

  • 二维数组的遍历
package com.bjpowernode.javase.array;

/**
	二维数组的遍历
	
 */
public class ArrayTest11 {

	public static void main(String[] args) {
		
		// 二维数组的遍历
		String[][] array = {
				{"c", "c++", "python", "java"},
				{"123", "456", "789"},
				{"abc", "def", "xyz", "bug"}
		};
		
		// 遍历二维数组
		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();
		}
	}

}

  • 动态初始化二维数组和二维数组作为方法参数
package com.bjpowernode.javase.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 ++) {
			for(int j = 0; j <array[i].length; j ++) {
				System.out.print(array[i][j] + " ");
			}
			System.out.println();
		}
		
		// 静态初始化
		int[][] a = {
				{1,2,3},
				{4,5,6,7},
				{8,9,10,11,12}
		};
		
		printArray(a);
		
		// 没有这种语法
		//printArray({{1,2,3},{4,5,6,7},{8,9,10,11,12}});
		// 改正写法
		//printArray(new int[][]{{1,2,3},{4,5,6,7},{8,9,10,11,12}});
		
	}
	
	public static void printArray(int[][] array) {
		// 遍历二位数组
		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();
		}
	}

}

数组涉及的算法

  • 常见的算法:
    • 排序算法
      • 冒泡排序算法
      • 选择排序算法
    • 查找算法
      • 二分法查找
  • 算法实际上在java中不需要精通,因为java中已经封装好了,要排序就调用方法就行。例如:java中提供了一个数组工具类
    • java.util.Arrays
      • Arrays是一个工具类
      • 其中有一个sort()方法,可以排序。静态方法:直接使用类名调用即可。
package com.bjpowernode.javase.array;

import java.util.Arrays;

/**
 	使用以下SUN公司提供的数组工具类:java.util.Arrrays;
 */
public class ArraysTest01 {

	public static void main(String[] args) {
		
		int[] arr = {2,34,5,67,8,1};
		
		// 工具类中的方法大部分都是静态的。
		Arrays.sort(arr);
		
		// 遍历输出
		for(int i = 0; i < arr.length; i ++) {
			System.out.println(arr[i]);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值