初识java - 数组的定义与使用
一,数组的基本概念
1.1什么数组
数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。
1.2数组的创建及初始化
1.2.1数组的创建
T[] 数组名 = new T[N];
- T 表示数组中元素的数据类型
- T[] 表示数组的数据类型
- N 表示数组长度(最大存放数据的个数)
例:
int[] array = new int[5];//创建了一个能容纳5个元素类型为int的数组
double[] array = new double[5];//创建了一个能容纳5个元素类型为double的数组
String[] array = new String[5];//创建了一个能容纳5个元素类型为String的数组 (注意:是String,不是string)
1.2.2数组的初始化
数组的初始化分为动态初始化和静态初始化
动态初始化:在创建数组时直接指定元素个数。
int[] array = new int[10];
double[] array = new double[10];
String[] array = new String[10];
- 注意如果没有对数组进行初始化,数组中元素有其默认值:
引用数据类型的默认值为null,如String
静态初始化:在创建数组时不直接指定数据元素个数,而直接将具体的数据内容进行指定。
int[] array = {1,2,3,4,5};//一般用这种方式进行静态初始化
int[] array = new int[]{1,2,3,4,5};
如果写成int[] array = new int[5]{1,2,3,4,5};编译器会报错
1.2.3二维数组的定义与使用
1.2.3.1二维数组的定义
T[][] 数组名= new T[M][N];
- T 表示数组中元素的数据类型
- T[][] 表示数组的数据类型
- M 表示数组有几行(只是这样表达,但是在内存上存储并不是这样的)
- N表示数组有几列(只是这样表达,但是在内存上存储并不是这样的)
【一张图带你了解二维数组】
二维数组是一个特殊的一维数组
1.2.3.2二维数组的使用
public static void main(){
int[][] array = {{1,2,3},{4,5,6}};
printArray(array);
}
//打印二维数组
public static void printArray(int[][] array){
//外层for循环为行
for (int i = 0; i < array.length; i++) {
//内层for循环为列
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j] + " ");
}
//换行
System.out.println();
}
---------
1 2 3
4 5 6
public static void main(String[] args) {
//二维数组
int[][] array = {{1,2,3},{1,2,3}};
//Arrays中打印二维数组的方法
System.out.println(Arrays.deepToString(array));
for (int i = 0; i < array.length; i++) {
System.out.println(Arrays.toString(array[i]));
}
}
-----------
[[1, 2, 3], [1, 2, 3]]
[1, 2, 3]
[1, 2, 3]
1.2.3.3不规则二维数组
public static void mainRandom(String[] args) {
//不规则二维数组
int[][] array = {{1,2},{3,4,5}};
printArray(array);
System.out.println(Arrays.deepToString(array));
}
----------
1 2
3 4 5
[[1, 2], [3, 4, 5]]
1.3数组的使用
数组是在内存中一块连续的空间中进行存储的,可以通过下标(索引)来对其中的元素进行访问,数组的其实下标(索引)为0。当然也可以通过下标(索引)对数组元素进行修改。
例:访问元素
int[] array = {1,2,3,4,5};
我想拿到数组中的数字3就可以通过
int number = array[2];
例:修改元素
1.4数组的遍历
int[] array = {1,2,3,4,5};
//for循环遍历数组
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] +" “);
}
System.out.println(); //隔行
//增强for循环遍历 – foreach
for (int x:array) {
System.out.print(x +” ");
}
System.out.println(); //隔行
//java.uitl.Arrays包下的方法遍历数组
System.out.println(Arrays.toString(array));
二,数组是引用类型
2.1初始JVM的内存分布
- 程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址。
- java栈(虚拟机栈)(JVM Stack): 与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
- 本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的。
- 堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销
毁。 - 方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域。
现在我们只简单关心堆 和 虚拟机栈这两块空间,后序JVM中还会更详细介绍。
2.2 基本类型变量与引用类型变量的区别
基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;
而引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址。
从上图可以看到,引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始地址。通过该地址,引用变量便可以去操作对象。类似C语言中的指针,但是Java中引用要比指针的操作更简单。
2.3数组作为参数在传参上的数据变动
三,数组的应用场景(cv程序猿)
3.1 保存数据
public static void main(String[] args) {
int[] array = {1, 2, 3};
for(int i = 0; i < array.length; ++i){
System.out.println(array[i] + " ");
}
}
3.2 作为函数的参数
- 参数传基本数据类型
public static void main(String[] args) {
int num = 0;
func(num);
System.out.println("num = " + num);
}
public static void func(int x) {
x = 10;
System.out.println("x = " + x);
}
// 执行结果
x = 10
num = 0
- 参数传数组类型(引用数据类型)
public static void main(String[] args) {
int[] arr = {1, 2, 3};
func(arr);
System.out.println("arr[0] = " + arr[0]);
}
public static void func(int[] a) {
a[0] = 10;
System.out.println("a[0] = " + a[0]);
}
// 执行结果
a[0] = 10
arr[0] = 10
3.3 作为函数的返回值
- 比如:获取斐波那契数列的前N项
public class TestArray {
public static int[] fib(int n){
if(n <= 0){
return null;
}
int[] array = new int[n];
array[0] = array[1] = 1;
for(int i = 2; i < n; ++i){
array[i] = array[i-1] + array[i-2];
}
return array;
}
public static void main(String[] args) {
int[] array = fib(10);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
四. 数组练习
4.1 冒泡排序
public static void main(String[] args) {
//冒泡排序
int[] array = {1, 3 , 2 , 4 ,5 ,6 ,7 , 8 ,9};
newBubSort(array);
System.out.println(Arrays.toString(array));
}
//冒泡排序优化版
public static void newBubSort(int[] array){
//判断数组是否已经有序
int boolSort = 0;
//循环计数
int count = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if(array[j] > array[j + 1]){
int tmp = array[j];
array[j] = array[j + 1];
array[j + 1] = tmp;
boolSort++;
}
count++;
}
//判断数组是否在第一次循环后是否有序
if(boolSort <= 1){
break;
}
}
System.out.println(count);
}
//冒泡排序
public static void bubSort(int[] array){
//循环计数
int count = 0;
for (int i = 0;i < array.length - 1;i++){
for (int j = 0;j < array.length - 1 - i;j++){
if(array[j] > array[j + 1]){
int tmp = array[j];
array[j] = array[j + 1];
array[j + 1] = tmp;
}
count++;
}
}
System.out.println(count);
}
4.2 逆置数组
public static void main(String[] args) {
//逆置数组
int[] array = {1,2,3,4,5,6,7,8,9};
reverseArray(array);
System.out.println(Arrays.toString(array));
}
//逆置数组
public static void reverseArray(int[] array){
int left = 0;//左边界下标
int right = array.length - 1;//右边界下标
while(left < right){
int tmp = array[left];
array[left] = array[right];
array[right] = tmp;
left++;
right--;
}
}
4.3 偶先奇后
public static void main(String[] args) {
//将数组中偶数先输出,奇数后输出
int[] array = {1,3,5,7,9};
arrayOddEven(array);
System.out.println(Arrays.toString(array));
}
//奇,偶交换
public static void arrayOddEven(int[] array){
int left = 0;
int right = array.length - 1;
while(left < right){
//left找奇数 right找偶数
if(array[left] % 2 == 0 && array[right] % 2 != 0){
left++;
right--;
}else if(array[left] % 2 == 0 ){
left++;
}else if(array[right] % 2 != 0){
right--;
}else{
int tmp = array[left];
array[left] = array[right];
array[right] = tmp;
}
}
}
4.4数组拷贝
public static void main(String[] args) {
//数组的拷贝
//有三种
int[] array = {1,2,3,4,5};
//第一种常用拷贝方式
/* //[I@1b6d3586
//[I@4554617c
//int[] arr = cpySArray(array);
//System.out.println(arr);
//System.out.println(Arrays.toString(arr));
//[I@1b6d3586
//[I@1b6d3586
//int[] arr = cpyQArray(array);
//System.out.println(arr);
//System.out.println(Arrays.toString(arr));*/
//第二种java.util.Arrays包下的copyOf方法或者copyOfRang方法
/*//返回一个从数组array中拷贝了array.length长度的数组
int[] arr1 = Arrays.copyOf(array, array.length);
//同时也可以实现扩容
int[] arr3 = Arrays.copyOf(array,array.length*2);
System.out.println(Arrays.toString(arr3));
//返回一个指定拷贝位置的数组
int[] arr2 = Arrays.copyOfRange(array, 2, 4);
System.out.println(Arrays.toString(arr2));*/
//第三种由native修饰的方法 -- 一般都是由c/c++已经实现了的方法
//优点速度快
/*int[] arr = new int[array.length];
System.arraycopy(array,0,arr,0,arr.length);
System.out.println(Arrays.toString(arr));*/
//第四种克隆拷贝
/*int[] arr = array.clone();
System.out.println(array);
System.out.println(arr);
arr[0] = 10;
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(arr));*/
}
//第一种常用拷贝
public static int[] cpySArray(int[] array){
// 直接在堆里开辟一块内存来存放数据
int[] arrayCpy = new int[array.length];
for (int i = 0; i < array.length; i++) {
arrayCpy[i] = array[i];
}
return arrayCpy;
}
public static int[] cpyQArray(int[] array){
int[] arrayCpy = array;
return arrayCpy;
}