Java入门part4——数组

数组

数组的定义

  • 数组:相同类型数据的集合 内存是连续的
  • 定义方法:
    (1) int[] arr={1,2,3,4}; 静态初始化
    (2)int[] arr=new int[]{1,2,3,4}; 动态初始化
    这两种定义的时候[]内是不能出现数组长度的
    === 》所以如果要知道数组长度 数组名.length求数组长度,其中 length不是方法 是一个属性
    (3)int[] arr=new int[5]; 未初始化 只是产生了一段空间
    注意:
  • 数组名里放的是数组首元素地址 ===》所以arr叫做引用(用来存放数组的地址)
  • 下标访问操作不能超出有效范围 [0, length - 1] , 如果超出有效范围, 会出现下标越界异常java.lang.ArrayIndexOutOfBoundsException
  • 当定义好数组之后没有初始化,数组当中如果是简单类型默认值为0 如果是引用类型那么默认值就是null

数组的遍历

  • for循环
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}
  • foreach循环
for(表达式1(数组中的变量):表达式2(数组名)){   
	System.out.print(x+" ");
}   

例如

 for(int x : arr){
	System.out.print(x+" ");
 }    

数组作为方法的参数

Java中数组的内存分析
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

在这里插入图片描述
==》此处可发现在函数内部改变参数的值,函数外面也发生了改变
因为此时的函数名arr是一个引用,此时传参是按引用传参
所谓的 “引用” 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实只是将数组的地址传入到函数形参中. 这样可以避免对整个数组的拷贝(数组可能比较长, 那么拷贝开销就会很大).

Java中数组的存储

Java中数组在堆上存储而不在栈上

JVM区域划分

在这里插入图片描述
在这里插入图片描述

  • Java虚拟机栈:存放局部变量

  • 本地方法栈:存放native方法 底层由C语言或C++实现 速度快

  • 程序计数器(PC register):存放下一条要执行的指令

  • 堆:放的是对象 通过new关键字new出来的

  • 方法区: 静态变量 类的信息

  • 常量池:用来存放字符串常量 String str=“hello”;
    在JDK1.7之前 常量池在方法区当中
    在JDK1.7开始,被挪到堆当中

  • 每一个线程都有程序计数器 jvm虚拟机栈和本地方法栈
    null 是所有引用类型的初始值

  • 数组名.length 字符串名.length()
    点号之前如果是null 大概率情况下肯定会出现空指针异常
    空指针异常 java.lang.NullPointerException

  • System.out.println(Arrays.toString(array)); 将数组以字符串类型输出 要导入包alt+enter

数组作为方法的返回值

/** 将数组中每个元素都乘以2* */
public class com {
    public static int[] fun(int[] arr){
        for (int i = 0; i <4 ; i++) {  
            arr[i]=arr[i]*2;        
        } 
        return arr;
    }
    public static void main(String[] args) {
        int[] arr={1,2,3,4};
        int[] arr2=fun(arr);
        for (int x:arr2) {    
                System.out.print(x+" ");
        }
     }
 }

由于数组是引用类型, 返回的时候只是将这个数组的首地址返回给函数调用者, 没有拷贝数组内容, 从而比较高效.

  • 可以通过javap -c进行反汇编

数组的应用

数组拷贝

int[] arr={2,3,4};
int[] arr2=new int[arr.length];
  1. 拷贝方式1
    arraycopy(Object src, int srcPos, Object dest, int destPos, int length) //将指定源数组中的数组从指定位置复制到目标数组的指定位置。 (原数组,从原数组第几号下标开始拷,目标数组,放到目标数组第几号下标,拷贝多长)
    需要new才能使用
  2. 拷贝方式2
    arr2=Arrays..copyOf(arr,arr.length);
    不需要new 深拷贝 深拷贝的定义见下
  3. 拷贝方式3
    利用for循环拷贝
  4. 拷贝方式4
    原数组名.clone() 用的较少
  • System.arraycopyArrays..copyOf的区别和联系
    查原码发现
    System.arraycopy是被native底层使用C语言写的 所以拷贝速度快
    Arrays..copyOf方法内部调用了 System.arraycopy()所以相较于System.arraycopy速度慢

以上四种拷贝方式对存放简单类型的数组来讲是深拷贝
对存放引用类型的数组来讲是浅拷贝

  • 深拷贝和浅拷贝
    • 深拷贝
      修改原有变量不会改变新拷贝的变量
    • 浅拷贝
      如果是两个引用同时指向一个对象 那么通过一个引用修改当前对象的值后 那么另一个引用也会受到影响 这种拷贝就叫做浅拷贝
  • 注意
    int[] arr={1,2,3};
    int[] arr2=arr; 这个不是拷贝

二维数组

   int[][] arr={{1,2},{3,4},{5,6}};
   int[][] arr=new int[][]{{1,2},{3,4},{5,6}};
   int[][] arr=new int[3][2];

不规则的二维数组

  int[][] arr=new int[3][];
  int[][] arr={{1},{3,4},{5,6}};
  • 打印二维数组除了遍历还可以System.out.println(Arrays.toString(array));返回指定数组的内容的字符串表示形式将其打印

  • 不规则数组的打印如果用寻常遍历方式会出现数组越界 所以应将条件改为i<arr.length j<arr[i].length

Arrays工具类的使用

Arrays.equals(arr,arr2);//判断两数组是否相同
Arrays.fill(arr,9);//将arr中全部填充为9
Arrays.fill(arr,2,6,9) ;//将arr中从下标2到5全部填充为9
Arrays. sort(arr); //对数组中的元素排序,底层是用双轴快速排序
Arrays.toString(arr);//返回指定数组的内容的字符串表示形式。
Arrays.deepToString(arr);//返回指定数组的“深度内容”的字符串表示形式。
Arrays.copyOfRange(int[] original, int from, int to);//将指定数组的指定范围复制到新数组中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章