4.1 内存分析
- Java 内存简单分析图
- 简单说明:
- 堆空间(heap):是不连续的空间,用于存放 new 出的对象,或者说是类的实例
- 栈空间(stack):连续的存储空间,遵循后进先出的原则,用于存放局部变量
- 方法区(method):方法区在堆空间内,用于存放:类的代码信息、静态变量和方法、常量池(字符串常量等,具有共享机制)等等
4.2 数组
4.2.1 简单运用
-
简单介绍
- 数组是多个相同类型数据的有序集合的数据结构
- 每一个数据称作一个数组元素,每个数据元素可以通过下标来访问
-
声明数组的语法格式:
dataType[] arrayRefVar; //首选方法 dataType arrayRefVar[]; //非首选
方括号写到变量名前面和后面效果相同
后者是跟C 和 C++ 相同的写法
-
例如:声明一维数组
int[] a; doubule []b; Mydate []c;
-
-
创建数组的语法格式:
dataType[] arrayRefVar = new dataType[arraySize];
-
例如:创建一维数组
int []a = new int[3]; a[0] = 3; a[1] = 4; a[2] = 2; MySDate []dates = new MyDate[3]; dates[0] = new MyDate(22,7,1945); dates[1] = new MyDate(22,8,2022); dates[2] = new MyDate(2,12,2000);
-
-
声明数组时不能同时创建数组(数组中元素的个数)
- 例如:
int[5];
这是一个在 Java 的非法的声明- 因为数组是引用类型,这里的 a(上面那个例子)只是一个引用
- 例如:
-
访问:通过索引进行访问,数组索引从 0 开始
-
index 为数组的下标,可以是整型常量或者整型表达式
- 例如:
a[1]
、b[i]
、c[6*i]
- 例如:
-
数组元素的下标从 0 开始;长度为 n 的数组合法下标取值范围:[0,n-1]
-
每一个数组都有一个属性 length ,用于指明数组长度,常用于循环
- 例如:
a.length
指明数组 a 的长度
- 例如:
-
-
复制数组
- 数组复制的常用方法有 4 种
- for 循环,效率最低
- System.arraycopy() 效率最高
- Arrays.copyOf() 效率次于第二种方法
- Object.clone() 效率次于第二种和第三种
- 数组复制的常用方法有 4 种
-
基本特点:
- 长度确定。数组一旦被创建,大小就不可变
- 元素类型为相同类型,不允许出现混合类型
- 数组的元素类型可以是任何数据类型,包括基本类型和引用类型
- 数组变量属于引用类型,数组对象本身是在堆中
4.2.2 三种初始化
-
静态初始化:在定义数组的同时就为数组元素分配空间并赋值
int[] a = {3,2,1}; //形式1 int[] a = new int[]{3,2,1}; //形式2 MyDate dates = { new MyDate(22,7,1945) };
int 例子中是两种方式都可以使用
最后可用多写一个逗号,如{3,2,1,}
-
动态初始化:在定义时分配空间和赋值分开进行
-
int[] a = new int[2]; a[0] = 1; a[1] = 2;
-
动态初始化也包括默认初始化
-
-
默认初始化:不进行赋值操作
- 因为数组是引用类型,所以数组一经分配空间,其中的每个元素也将按照成员变量同样的方式被隐式初始化
- 数值类型是 0,引用类型是 null
- 例如:
int [] a = new int[5];
如果输入a[3]
结果将是 0
- 因为数组是引用类型,所以数组一经分配空间,其中的每个元素也将按照成员变量同样的方式被隐式初始化
4.2.3 数组的使用
-
普通的 for 循环
-
For-Each 循环(增强 for 循环)
-
jdk1.5 以后的方法,没有下标
-
示例:
package exercise; public class arrayFor { public static void main(String[] args) { int[] arrays = {1,23,4,45}; for (int array : arrays) { System.out.print(array); } } }
123445
-
快捷键调用:
数组名.for
-
-
数组作为参数
-
数组作为返回值
4.2.4 多维数组
-
多维数组:可以认为是数组的数组,例如二维数组就是一个特殊的一维数组,每个元素就是一个一维数组
-
例如:生成一个二维数组
int[][] a = {{1,2},{3,4,0,9},{5,6,7}};
- 图示:
- 图示:
-
多维数组的声明初始化应按照从高维到低维的顺序进行
-
例如:
int[][] t = new int [3][]; t[0] = new int[2]; t[1] = new int[3]; t[2] = new int[4]; …… int[][] x = new int [3][3];
-
不能写为
int t1 [][] = new int [][4];
这与 C++ 不同
-
4.3 Arrays 类
-
数组对象本身没有提供什么方法供其调用,而 API 提供了一个工具类 Arrays 来对数组对象进行一些操作
- 数组的工具类 java.util.Arrays
-
Arrays 的 方法都是通过 static 修饰的静态方法,在使用时可以直接使用类名进行调用,而不通过使用对象来调用
-
常用功能:
方法 描述 fill() 数组赋值 sort() 数组升序排序 equals() 比较数组中的元素是否相等 binarySearch() 对已经排序的数组进行二分法查找法 -
例如:使用 Arrays 排序再输出
package exercise; import java.util.Arrays; public class arrayFor { public static void main(String[] args) { int[] a = {1,23,4,45}; Arrays.sort(a); System.out.println(Arrays.toString(a)); } }
[1, 4, 23, 45]
4.4 冒泡排序
-
冒泡排序是八大排序方法中可以说最出名的排序方法
-
实现方法:
- 两层循环,外层冒泡轮数,里层依次比较
-
示例代码:
package exercise; import java.util.Arrays; public class BubblingSort { public static void main(String[] args) { int[] a = {1,5,3,42,2,345,6}; int[] sort = sort(a); System.out.println(Arrays.toString(sort)); } public static int[] sort(int[] array){ int temp = 0; for (int i = 0; i < array.length-1; i++) { for (int j = 0; j < array.length-1-i; j++) { if (array[j+1]>array[j]){ temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } } return array; } }
[345, 42, 6, 5, 3, 2, 1]
4.5 稀疏数组
-
定义:稀疏数组可以看做是普通数组的压缩,这里普通数组是指在需求数据中无效数据量远大于有效数据量的数组
-
例如:
的稀疏数组为
-
-
用途:当一个数组大部分元素为 0,或者为同一值的数组时,可以采用稀疏数组来保存该数组
- 为什么要保存数组
- 原数组中存在大量的无效数据,占据了大量的存储空间,真正有用的数据却少之又少
- 压缩存储可以节省存储空间以避免资源的不必要的浪费,在数据序列化到磁盘时,压缩存储可以提高 I/O 效率
- 为什么要保存数组
-
示例:将上面的例子用代码表示出来的一种方式
package exercise; import java.util.Arrays; public class SparceArrays { public static void main(String[] args) { //创建普通数组 int[][] arrays1 = new int[11][11]; arrays1[1][2] = 1; arrays1[2][3] = 2; //打印普通数组 System.out.println("原始数组"); for (int[] ints : arrays1) { for (int anInt : ints) { System.out.print(anInt+"\t"); } System.out.println(); } //转换为稀疏数组 //获取有效值的个数 int sum = 0; for (int i = 0; i < 11; i++) { for (int j = 0; j < 11; j++) { if (arrays1[i][j] != 0){ sum++; } } } System.out.println("有效值的个数:"+sum); //创建一个稀疏数组 int[][] arrays2 = new int[sum+1][3]; arrays2[0][0] = 11; arrays2[0][1] = 11; arrays2[0][2] = sum; //遍历普通数组 int count = 0; for (int i = 0; i < arrays1.length; i++) { for (int j = 0; j < arrays1[i].length; j++) { if(arrays1[i][j] != 0){ count++; arrays2[count][0] = i; arrays2[count][1] = j; arrays2[count][2] = arrays1[i][j]; } } } //打印稀疏数组 System.out.println("稀疏数组"); for (int i=0; i<arrays2.length;i++) { System.out.println(arrays2[i][0]+"\t"+arrays2[i][1]+"\t"+arrays2[i][2]+"\t"); } //还原稀疏数组 //1.读取稀疏数组 int[][] arrays3 = new int[arrays2[0][0]][arrays2[0][1]]; //2.还原原数组 for (int i = 1; i < arrays2.length; i++) { arrays3[arrays2[i][0]][arrays2[i][1]] = arrays2[i][2]; } //输出原始数组 System.out.println("原始数组"); for (int[] ints : arrays1) { for (int anInt : ints) { System.out.print(anInt+"\t"); } System.out.println(); } } }
运行结果:
原始数组 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 有效值的个数:2 稀疏数组 11 11 2 1 2 1 2 3 2 原始数组 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0