JavaSE 数组
程序员文章站
2022-07-04 14:04:25
...
Java自我学习路线
一、数组的定义
- 数组是数据的集合,实际上是一个容器,可以同时容纳多个元素
- 在Java中规定,数组一旦创建,数组长度不可变
- 所有的数组对象都有length属性(Java自带属性),用来获取数组中元素的个数
System.out.println(arr.length); //数组用的是length属性,后面不加(),String字符串用的是length方法,后面加()
- 数组实际上是一种简单的数据结构
二、数组的类型
- Java语言中的数组是一种引用数据类型,不属于基本数据类型,数组的父类是Object,但是数组当中可以存储基本数据类型或引用数据类型的数据,且Java中要求数组中的元素类型统一,比如int类型数组只能存储int类型,Person类型只能存储Person类型
三、数组在内存中的存储
- 数组中不能直接存储Java对象,实际上存储的是对象的内存地址,而对象是存储在堆内存当中,即数组中存储内存地址,这个内存地址指向堆内存中的对象
- 数组在内存存储的时候,数组中元素的内存地址是连续的,且每个元素占用的空间大小相同
- 数组中首元素的内存地址作为整个数组对象的地址
- 数组中每个元素都有下标,下标从0开始,以1递增,最后一个元素的下标是length-1,对数组中元素进行“存取”的时候,都需要通过下标来进行
四、数组的优点和缺点
- 优点
查询/检索某个下标对应的元素效率极高
原因:
1. 每一个元素的内存地址在空间存储上是连续的
2. 每一个元素数据类型相同,所以占用空间大小一样
3. 已知元素内存地址、元素占用空间的大小、下标,可以方便的通过一个数学表达式计算出某个下标上元素的内存地址(偏移量),即直接通过内存地址定位元素 - 缺点
1. 随机增删效率较低(最后一个元素除外)
原因:
为了保证数组中每个数组元素的内存地址连续,增删时会涉及到某些元素向前或向后位移的操作
2. 数组无法存储大数据量
原因:
很难在内存空间上找到一块特别大的连续的内存空间
五、数组的分类
一维
二维(元素为一维数组的数组)
多维(数组元素是数组的数组)
…
六、数组的初始化
-
静态初始化(创建数组时,已确定数组中存储哪些具体的元素,采用静态方式)
一维数组的静态初始化
int[] arr = {1,2,3,4};
Object[] objs = {new Object(),new Object(),new Object(),new Object()};
......
二维数组的静态初始化
int[][] arr = {
{1,2,3,4},
{5,6},
{1,8,9},
{-1,-5}
}
Object[] objs = {
{new Object(),new Object()},
{new Object()},
{new Object()}
};
......
-
动态初始化(创建数组时,不确定将来数组中存储哪些元素,采用动态方式,预先分配内存空间)
一维数组的动态初始化
int[] arr = new int[5]; //5表示数组的元素个数(初始化5个长度的int连续数组,每个元素默认值为0)
String[] arr = new String[6]; //初始化6个长度的String类型数组,每个元素默认值为null
二维数组的动态初始化
int[][] arr = new int[3][4];
int[][] arr = new int[3][];
int[][] arr = new int[][4]; //错误
Object[][] arr = new Object[3][4];
Object[][] arr = new Object[3][];
Person[][] arr = new Person[3][4]; //Person类型数组,里面可以存储Person类型对象以及Person类型的子类型
......
七、数组的遍历
- 一维数组的遍历
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
- 二维数组的遍历
for(int i = 0;i < arr.length;i++){
for(int j = 0;j < arr[i].length;j++){
System.out.prnintln(arr[i][j]);
}
System.out.prnintln();
}
八、输出整个数组
使用java.util.Arrays工具类
工具类中的方法都是静态方法,直接使用类名调用即可
- Arrays.toString();
Arrays.toString(); 中不能传值,应该传变量名(任意数据类型)
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4 };
System.out.println(Arrays.toString(arr)); //输出[1, 2, 3, 4]
}
}
- 若是直接System.out.println(arr)会是什么情况?:
public class Test {
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4 };
System.out.println(arr);
}
}
[aaa@qq.com
[I:表示数组对象,@表示字符,后面使用8位16进制数保存内存的地址
- API:
public static String toString(int[] a) {
if (a == null)
return "null"; // 不是值,在内存中没有地址,是一个字符串“null”
int iMax = a.length - 1; //最后一个元素的下标索引
if (iMax == -1)
return "[]"; // 创建了一个数组对象,并且在内存当中有地址,只不过值为空(空数组元素)
StringBuilder b = new StringBuilder(); // StringBuilder可变长字符串
b.append('[');
for (int i = 0; ; i++) { // 无条件,拿出所有元素
b.append(a[i]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
- 特殊:char类型:
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
char[] arr = new char[10];
System.out.println(arr);
System.out.println(Arrays.toString(arr));
}
}
System.out.println(arr); 输出:不为空,但不显示
System.out.println(Arrays.toString(arr)); 输出:不为空,值为 \u0000,用“,”隔开
利用循环赋值继而显示值
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
char[] arr = new char[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = (char) ('0' + i);
}
System.out.println(arr);
System.out.println(Arrays.toString(arr));
}
}
九、数组的赋值与复制
- for循环实现数组的赋值
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr1 = { 1, 2, 3, 4 };
int[] arr2 = new int[arr1.length];
for (int i = 0; i < arr1.length; i++) {
// 将arr1中的每个元素赋值给arr2中的每个元素
arr2[i] = arr1[i];
}
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
}
}
- System.arraycopy(src, srcPos, dest, destPos, length); 实现数组的复制
C++实现的复制(拷贝), native(调用C++)
src, srcPos, dest, destPos, length:
原数组、位置(原从哪拷贝)、目标数组、位置(目标从哪拷贝)、长度(拷贝多长)
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr1 = { 5, 6, 7, 8 };
int[] arr2 = new int[arr1.length];
System.arraycopy(arr1, 0, arr2, 0, arr1.length); //全复制(拷贝)
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
}
}
十、数组的扩容/缩容
- Arrays.copyOf(original, newLength); 实现数组的扩容/缩容
original, newLength:
要拷贝的数组,新长度
API:
public static int[] copyOf(int[] original, int newLength) {
int[] copy = new int[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
测试:
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr1 = { 5, 6, 7, 8 };
int[] arr2 = Arrays.copyOf(arr1, 5);
arr2[arr2.length - 1] = 34;
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
}
}
十一、数组的排序
- Arrays.sort(); 默认升序,无返回值
测试:
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr1 = { 1, 9, -6, 23, 34 };
Arrays.sort(arr1);
System.out.println(Arrays.toString(arr1));
}
}
补充一:选择排序
- 将数组中每个元素与第一个元素比较,如果这个元素小于第一个元素,则交换这两个元素
package com.lzj.demo;
import java.util.Arrays;
/**
* 选择排序 将数组中每个元素与第一个元素比较,如果这个元素小于第一个元素,则交换这两个元素
*
* @author lzj
* @version 1.0
*/
public class SelectionSort {
public static void main(String[] args) {
int[] arr = { 51, 2, 34, -12, 4, 12 };
arr = sort(arr);
System.out.println(Arrays.toString(arr));
}
/**
* 选择排序
*
* @param arr 待排序数组
* @return 排好序数组
*/
public static int[] sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
}
补充二:冒泡排序
- 比较相邻的元素,将小的放到前面,
package com.lzj.demo;
import java.util.Arrays;
/**
* 冒泡排序 比较相邻的元素,将小的放到前面
*
* @author lzj
* @version 1.0
*/
public class BubbleSort {
public static void main(String[] args) {
int[] arr = { 51, 2, 34, -12, 4, 12 };
arr = sort(arr);
System.out.println(Arrays.toString(arr));
}
/**
* 冒泡排序
*
* @param arr 待排序数组
* @return 排好序数组
*/
public static int[] sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
}
补充三:二分查找
- 前提:带查找数组是已排好序的
package com.lzj.demo;
/**
* 二分查找
*
* @author lzj
* @version 1.0
*/
public class BinarySearch {
public static void main(String[] args) {
// int[] arr = { 1, 345, 56, 8, 6 };
int[] arr = { 1, 5, 6, 8 };
// int[] arr = { 9, -2, 5, 6 };
int index = sort(arr, 6);
System.out.println(index == -1 ? "该元素不存在!" : "该元素下标" + index);
}
/**
*
* @param arr 带查找已排序数组
* @param dest 目标元素
* @return -1表示该元素不存在,其他表示返回该元素的下标
*/
public static int sort(int[] arr, int dest) {
// 开始下标
int begin = 0;
// 结束下标
int end = arr.length - 1;
// 开始元素的下标只要在结束元素下标的左边,就有机会循环
while (begin <= end) {
// 中间下标
int mid = (begin + end) / 2;
if (arr[mid] == dest) {
// 中间值与目标相等
return mid;
} else if (arr[mid] < dest) {
// 目标在中间的右边
begin = mid + 1;
} else {
// 目标在中间的左边
end = mid - 1;
}
}
return -1;
}
}