1. 数组
* 数组是引用数据类型,用来保存多个数据
1.1 数据结构
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关
数据操作 : 增删改查
1.2 数组特性
* 数组特性 :
* 内存中连续存储,并且下标从0开始(内存地址偏移)
* 数组长度一旦确定 长度不能更改,也就意味着数组是不能添加和删除的
* 除非新建一个数组,把原数据复制到新数组中,在复制的过程当中可以进行添加和删除操作
* 所以 数组的查询和更改 效率是很高的,但是 添加和删除效率较低
* 数组都有一个内置属性 length 保存了数组的长度
* 在java中 有一个java.util.Arrays 类 提供了一些数组操作
1.3 数组声明
* 数组声明
* 1 静态声明 : 在已知每个元素的时候,使用静态声明
* 数据类型 变量名 = 值;
* int i = 2;
* 数据类型[] 变量名 = {值,值,值.....}; 简写方式
* 数据类型[] 变量名 = new 数据类型[]{值,值,值......}; 比如对数组进行二次赋值,就需要这样写
* int[] arr = {1,2,3,6,1,2,3};
* int[][] arr = {
* {1,2,3},{2,1,3},{4,6}
* };
* 2 动态声明 : 不知道数组中每个元素的时候,使用动态声明
* 数据类型[] 变量名 = new 数据类型[长度];
* int[] arr = new int[5];
* int[][] arr = new int[2][3];
* 动态声明,保存的是对应类型的默认值,比如上面程序中 会保存5个0
* 整数 0 , 小数 0.0 , 布尔 false , 字符 \u0000 , 引用类型 null
public static void main(String[] args) {
// 静态声明
int[] arr = {1,2,3};
// 如果对数组二次赋值 必须这样写 , 不能直接写 {}
arr = new int[]{2,3,4};
int[] arr2 = new int[10];
// [] 也可以写到变量名后面
char arr3[] = {'a','2','c'};
}
1,4 存储方式
public static void main(String[] args) {
int[] arr = { 1, 2, 3 };
1.5 数组使用
1.5.1 获取数据
// 静态初始化一个数组
int[] arr = { 10, 11, 12, 2 };
// 获取 : 数组[下标] ,注意 下标从0开始
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
// 数组长度 : 数组.length
System.out.println(arr.length);
// 最后一个元素
System.out.println(arr[arr.length - 1]);
1.5.2 更改数据
// 更改 : 数组[下标] = 值;
arr[1] = 1;
System.out.println(arr[1]);
System.out.println("====");
1.5.3 遍历
// 遍历
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 增强for循环 foreach
// 把数组中的每一个元素,都赋值给变量
// for(数据类型 变量名 : 数组){}
for (int element : arr) {
System.out.println(element);
}
1.5.4 常见异常
- 1 下标越界
- java.lang.ArrayIndexOutOfBoundsException: 4
int[] arr = { 1, 2, 3, 4 };
// java.lang.ArrayIndexOutOfBoundsException: 4
// 下标越界,下标没有4 超出了
System.out.println( arr[4] );
- 2 空指针异常
- java.lang.NullPointerException
// 假如没有对数组进行初始化操作,默认是null
arr = null;
// java.lang.NullPointerException
// 如果数据没有进行初始化,但是对数组进行了属性操作,会导致 空指针异常
// System.out.println(arr.length);
System.out.println(arr[0]);
1.5.5 数组传递
public static void main(String[] args) {
int i = 2;
m1(i);
m1(22);
int[] arr = {1,2,3};
m2(arr);
// 数组字面量传递方式
m2( new int[]{1,2,3} );
}
public static void m1(int i){
}
public static void m2(int[] arr){
}
1.5.6 Main方法传参
1.6 传值和传址
* 传值 指的是传递基本类型的数据
*
* 传址/传引用 指的是传递引用数据类型的值
*
* 基本类型传递之后, 相互没有影响,因为指向不同的空间
*
* 引用类型传递之后,相互有影响,因为指向同一个堆内存对象空间
public static void main(String[] args) {
int i = 10;
m1(i);
// 10
System.out.println("main中的 i = "+i);
int[] arr = {1,2,3};
m2(arr);
System.out.println(arr[0]);
}
public static void m1(int i){
i = 20;
// 20
System.out.println("m1中的 i = "+i);
}
public static void m2(int[] arr){
arr[0] = 11;
System.out.println(arr[0]);
}
1.7 数组复制
- 数组复制
public static void main(String[] args) {
// copy();
int[] src = { 2, 3, 4, 5, 6, 7, 8 };
int[] dest = { 11, 12, 13, 14, 15, 16, 17, 18 };
// copy(src, dest, 2, 3, 3);
// 源数组 , 原数组起始位置(包含) , 目标数组 , 目标数组起始位置 , 复制个数
// 因为是替换式复制,只是把原来的数据更改了,并没有重新生成数组,所以不需要返回值,因为传引用...
System.arraycopy(src, 2, dest, 3, 3);
for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]);
}
}
public static void copy(int[] src, int[] dest, int srcPos, int destPos,
int length) {
// int[] src = { 2, 3, 4, 5, 6, 7, 8 };
// int[] dest = { 11, 12, 13, 14, 15, 16, 17, 18 };
// int[] dest = {11,12,13,4,5,6,17,18};
for (int i = srcPos, j = destPos; i < srcPos + length; i++, j++) {
dest[j] = src[i];
}
}
- 数组插入复制
public static void main(String[] args) {
int[] src = { 2, 3, 4, 5, 6, 7, 8 };
int[] dest = { 11, 12, 13, 14, 15, 16, 17, 18 };
// int[] dest = { 11, 12, 13, 14,4, 5, 6, 15, 16, 17, 18 };
int[] result = copy(src, 2, dest, 3, 3);
for (int i = 0; i < result.length; i++) {
System.out.println(result[i]);
}
}
/**
* 插入复制
*
* @param src
* 源数组
* @param srcPos
* 源数组起始位置
* @param dest
* 目标数组
* @param destPos
* 目标数组起始位置
* @param length
* 插入个数
* @return
*/
public static int[] copy(int[] src, int srcPos, int[] dest, int destPos,
int length) {
// 因为是插入复制,所以肯定会更改数组长度,因为数组长度不能更改,所以我们只能新建数组,并通过返回值把数组返回
/**
* 0 创建一个新数组,长度为 dest.length + length
*
* 1 目标数组中 从0开始 到 起始位置结束(包含),复制到新数组中
*
* 2 源数组中 从起始位置开始(包含) 复制 length个 到 新数组中
*
* 3 目标数组中 从起始位置+1开始(包含) 到最后 所有的数据 复制到新数组中
*/
// 0 创建一个新数组,长度为 dest.length + length
int[] newDest = new int[dest.length + length];
// 1 目标数组中 从0开始 到 起始位置结束(包含),复制到新数组中
for (int i = 0; i <= destPos; i++) {
newDest[i] = dest[i];
}
// 2 源数组中 从起始位置开始(包含) 复制 length个 到 新数组中
// 现在需要用到目标数组的起始位置并且需要更改,但是 后面还要用到目标数组的起始位置,所以我们不能更改
// 所以 这里把目标数组起始位置 赋值给一个新变量index,可以更改index
int index = destPos;
for (int i = srcPos; i < srcPos + length; i++) {
index++;
newDest[index] = src[i];
}
// 3 目标数组中 从起始位置+1开始(包含) 到最后 所有的数据 复制到新数组中
for (int i = destPos + 1; i < dest.length; i++) {
index++;
newDest[index] = dest[i];
}
return newDest;
}
2. 二维数组
2.1 声明方式
* 二维数组操作
*
* 声明 :
* 静态声明
* int[][] arr = {
* {1,2,3},
* {2},
* {2,5,1,6,8}....
* };
* 动态声明
* int[][] arr = new int[3][4]; 表示 该二维数组中,有3个一维数组,并且每个一维数组中都有4个数据
* int[][] arr = new int[3][]; 表示 该二维数组中 有三个一维数组,并且这三个一维数组都是 null
* 这种需要单独初始化每一个一维数组的长度,一般用于 每行列不一样的情况(每个一维数组中,元素个数不同的情况)
* arr[0] = new int[5];
* arr[1] = new int[15];
* arr[2] = new int[3];
// 静态
int[][] arr1 = {
{1,2,3,4},
{0},
{1,6},
{22,3,5,6,7,8,9}
};
// 表示 该二维数组中,有3个一维数组,并且每个一维数组中都有4个数据
int[][] arr2 = new int[3][4];
int[][] arr3 = new int[3][];
arr3[0]=new int[3];
arr3[1]=new int[33];
arr3[2]=new int[13];
2.2 存储方式
int[][] arr4 = {
{1,2,3},
{0,1,2},
{1,6},
{22,3,5,6}
};
2.3 使用方式
2.3.1 获取数据
// 获取数据 数组[下标][下标]
int[] arr0 = arr4[0];
int arr00 = arr0[0];
System.out.println(arr00);
System.out.println( arr4[0][0]);
System.out.println( arr4[3][1]);
int[] arr_3 = arr4[ arr4.length-1 ];
int arr_33 = arr_3[ arr_3.length -1 ];
System.out.println(arr_33);
System.out.println( arr4[ arr4.length-1 ][ arr4[ arr4.length-1 ].length -1 ]);
2.3.2 更改数据
// 更改 数组[下标][下标] = 值
arr4[3][1] = 33;
2.3.3 遍历
// 遍历
for (int i = 0; i < arr4.length; i++) {
// int[] arr4i = arr4[i];
// System.out.println(arr4i);
for (int j = 0; j < arr4[i].length; j++) {
System.out.print(arr4[i][j]+" ");
}
System.out.println();
}
2.3.4 动态声明锯齿状
public static void main(String[] args) {
// 二维表
int[][] arr = new int[5][6];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
// 锯齿状
int[][] arr1 = new int[5][];
// 初始化二维数组中的每一个一维数组
for (int i = 0; i < arr1.length; i++) {
arr1[i] = new int[i+1];
}
// 遍历
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr1[i].length; j++) {
System.out.print(arr1[i][j] + " ");
}
System.out.println();
}
}
3. 交换变量的值
public static void main(String[] args) {
int x = 10;
int y = 11;
// 1 中间变量(开发常用)
int temp = x;
x = y;
y = temp;
System.out.println("x=" + x + ",y=" + y);
// 2 位移运算(面试用)
x = 2; // 0000 0010
y = 3; // 0000 0011
// 转换为对应的二进制,每位异或,相同取0,不同取1
x = x ^ y; // 0000 0001
y = x ^ y; // 0000 0010
x = x ^ y; // 0000 0011
System.out.println("x=" + x + ",y=" + y);
// 3 加减运算
x = 10;
y = 20;
x = x + y;
y = x - y;
x = x - y;
System.out.println("x=" + x + ",y=" + y);
}