1.数组是啥?
数组是一块连续的内存,用来存储相同类型的数据
(1)如何定义数组?
1.int[] array = {1,2,3,4} = new int[]{1,2,3,4};//这里的new是一个关键字,用来创建对象
2.数组就是一个对象
动态初始化
java
int[] array = new int[10];//这个数组没有初始化时,默认将数组初始化为0
静态初始化
java
T[] 数组名称 = {data1, data2, data3, ..., datan};
还可以这样初始化
java
int[] array4;//局部变量
array4 = new int[10];
错误初始化
可以改成这样:
int[] array5 = null;//存储类型是引用类型时,用null
各类型数组初始化
(2)数组的创建
java
T[] 数组名 = new T[N];//N是数组长度
(3)数组越界
int[] array = {1,2,3,4}
获取数组长度:
java
int len = array.length;
System.out.println(len);
(4)遍历数组
java
//第一种遍历方式
int[] array = {1,2,3,4};
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
java
//第二种:增强for循环:for-each
for(int x: array){//在遍历这个数组的时候,把数组中的元素进行赋值给x
System.out.print(x + " ");
}
System.out.println();
区别:for遍历数组有带下标,for-each没有
2.数组是引用类型
(1)JVM的内存分布
虚拟机栈 (JVM Stack): 与方法调用相关的一些信息, 每个方法在执行时,都会先创建一个栈帧 ,栈帧中包含有:局部变量表 、 操作数栈 、 动态链接 、 返回地址 以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了 。
堆 (Heap) : JVM 所管理的最大内存区域 . 使用 new 创建的对象都是在堆上保存 ( 例如前面的 new int[]{1, 2, 3} ) , 堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销 毁 。
(2)数组-->引用
java
public static void func() {
int a = 10;
int b = 20;
int[] arr = new int[]{1,2,3};//描述为arr这个引用指向了一个数组对象
}
用arr里面的地址去操作对象里面的值
尝试分析下面的代码
java
public static void func() {
int[] array1 = new int[3];
array1[0] = 10;
array1[1] = 20;
array1[2] = 30;
int[] array2 = new int[]{1,2,3,4,5};
array2[0] = 100;
array2[1] = 200;
array1 = array2;
array1[2] = 300;
array1[3] = 400;
array2[4] = 500;
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i]);
}
}
⚠array1和array2的值都是地址
array2的值把array1原来的值顶掉了,array1从原来的0x89变成0x99
所以,通过array1这个引用,可以修改array2这个引用所指向的对象
(3)null
array = null 表示当前引用不指向任何对象,所以谈长度是没道理的
⚠Java里面null和0号地址没有任何关联
⚠一个引用不能同时指向多个对象(跟变量一样,只能一一对应存对象)
⚠对象不能指向对象,只有引用才能指向对象
3.数组的应用
(1)作为函数参数
(改变引用的值?改变引用对象的值?)
java
public static void main(String[] args) {
int[] array = {1,2,3,4};
/*
当我 分开调用func1和 func2
func1();
func2();
array这个数组 里面的值 分别是多少?
*/
//func1(array);
func2(array);
for (int x : array) {
System.out.print(x+" ");
}
System.out.println();
}
public static void func1(int[] array) {
array[0] = 99;
}
public static void func2(int[] array) {
array = new int[]{11, 22, 33, 44, 55};
}
运行结果
1.99 2 3 4
2.1 2 3 4
func1修改的是实参array下标为0的元素,打印出来就是99,2,3,4
而func2把形参从指向{1,2,3,4}改成指向{11,22,33,44,55},不影响实参,实参该是什么就是什么,所以是1,2,3,4
(2)作为函数返回值
java
public static void main(String[] args) {
int[] ret = func3();
for (int i = 0; i < ret.length; i++) {
System.out.println(ret[i]);
}
}
public static int[] func3(){
int[] ret = new int[2];
ret[0] = 99;
ret[1] = 199;
return ret;//作为返回值的形式进行传递
}
4.数组练习
(1)数组转字符串
一个打印数组比较便捷的方式,比for循环快多了
java
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
String ret = Arrays.toString(array);
System.out.println(ret);
}
(2)数组排序
使用Array的包
Arrays.sort(array,0,3);//区间排序,在[0,3)这个区间里面从大到小排序
我们自己做一个数组打印方法
java
public static String myToString(int[] array){
if (array == null){
return "null";
}
if (array.length == 0){
return "[]";
}
String ret = "[";
for (int i = 0; i < array.length; i++) {
ret += array[i];
if (i != array.length-1){//最后一个不打印","
ret+=", ";
}
}
ret += "]";
return ret;
}
(3)不妨再做一个sort的方法(冒泡排序)
排序[8,12,5,7,9]
现在已经是有序状态,但是系统不一定知道已经是有序的,所以我们要给机器一个验证
i是趟数,j是交换的次数
java
public static void bubbleSort(int[] array){
if(array == null){
return;
}
//i代表遍历趟数
for (int i = 0; i < array.length-1; i++) {
//每次比上一次少一个,优化:比较趟数
boolean flg = false;//优化:比较结果
//j代表元素下标,相当于C里面的指针
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;
flg = true;
}
}
if(!flg){
//没有交换
return;
}
}
}
public static void main(String[] args) {
int[] array = {8,12,5,7,9};
System.out.println(myToString(array));
bubbleSort(array);
System.out.println(myToString(array));
}
(4)逆置数组排序
java
public static void reverse(int[] array){
if (array == null){
return;
}
int i = 0;
int j = array.length-1;
while(i < j){
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
i++;
j--;
}
}
5.数组拷贝
java
public static void main(String[] args) {
int[] array1 = {2, 4, 6, 3};
int[] array2 = {2,4,6,3,10};
System.out.println(Arrays.equals(array1, array2));//equals判断数组是否相同
int[] array = new int[10];
System.out.println(Arrays.toString(array));
Arrays.fill(array, 9);
Arrays.fill(array, 0, 3, 9);
System.out.println(Arrays. toString(array));
}
java
public static void func(){
// copyOf方法在进行数组拷贝时,创建了一个新的数组
// arr和newArr引用的不是同一个数组
arr[0] = 1;
newArr = Arrays.copyOf(arr, arr.length);//扩容
System.out.println(Arrays.toString(newArr));
// 因为arr修改其引用数组中内容时,对newArr没有任何影响
arr[0] = 10;
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(newArr));
// 拷贝某个范围.
int[] newArr2 = Arrays.copyOfRange(arr, 2, 4);
System.out.println(Arrays.toString(newArr2));
int[] copy = new int[array1.length];
System.arraycopy(array1,0,copy,0,array1.length);
}
arraycopy的底层代码
6.二维数组
如何创建二维数组?
java
int[][] array = {{1,2,3},{4,5,6}};
//System.out.println(array[1][2]);
int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
int[][] array3 = new int[2][3];
//定义二维数组行不能省略
//int[][] array4 = new int[][3];这种是错误的
//不规则二维数组
int[][] array5 = new int[2][];
打印二维数组
我们常规以为的二维数组
所以就有下面的打印代码
java
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
而真正的二维数组是这样的
java
int[][] array = {{1,2,3},{4,5,6}};
System.out.println(array.length);
System.out.println(array[1].length);
System.out.println(array[2].length);
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
for (int[] tmp:array) {
for (int x : tmp) {
System.out.println(x + " ");
}
System.out.println();
}
给这个二维数组规定每行有哪些数