【Java】浅谈Java数组的定义与使用

【Java】浅谈Java数组的定义与使用_第1张图片

写在前边

前言
本篇博客主要讲述了以下几点问题


1. 理解数组基本概念
2. 掌握数组的基本用法
3. 数组与方法互操作
4. 熟练掌握数组相关的常见问题和代码~

【☕Java】浅谈Java数组的定义与使用

  • 写在前边
  • 数组基本用法
    • 什么是数组
    • 创建数组
    • 数组的使用
  • 数组作为方法的参数
    • 基本用法
    • 理解引用类型(敲黑板!!!)
    • 认识null
    • 初时JVM内存区域划分(敲黑板!!!)
    • 数组作为方法的返回值
  • 数组练习
    • 二分查找
    • 冒泡排序
    • 判断数组是否有序
    • 只出现一次的元素
    • 改变原有数组的值
    • 数组所以元素之和
    • 数组拷贝
    • 数组转字符串
    • 求数组元素平均值
  • 二维数组

数组基本用法

什么是数组

【数组】本质上就是让我们能 “批量” 创建相同类型的变量.

例如:
如果需要表示两个数据, 那么直接创建两个变量即可 int a; int b
如果需要表示五个数据, 那么可以创建五个变量 int a1; int a2; int a3; int a4; int a5;
但是如果需要表示一万个数据, 那么就不能创建一万个变量了. 这时候就需要使用数组, 帮我们批量创建.

注意事项: 在 Java 中, 数组中包含的变量必须是 相同类型.

创建数组

基本语法

动态初始化
数据类型[] 数组名称 = new 数据类型 [ ] { 初始化数据 };

如果在创建的同时不初始化数组则必须指定其大小
数据类型[] 数组名称 = new 数据类型 [元素个数] ;

静态初始化
数据类型[] 数组名称 = { 初始化数据 };

代码示例

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

注意事项: 静态初始化的时候, 数组元素个数和初始化数据的格式是一致的.

其实数组也可以写成
int arr[] = {
      1, 2, 3};

这样就和 C 语言更相似了. 但是更推荐写成 int[ ] arr 的形式. int和 [ ] 是一个整体.

数组的使用

代码示例: 获取长度 & 访问元素

int[] arr = {
      1, 2, 3}; 
// 获取数组长度 
System.out.println("length: " + arr.length); // 执行结果: 3 
// 访问数组中的元素 
System.out.println(arr[1]); // 执行结果: 2 
System.out.println(arr[0]); // 执行结果: 1 
arr[2] = 100; 
System.out.println(arr[2]); // 执行结果: 100

注意事项
1. 使用 arr.length 能够获取到数组的长度【. 】这个操作为成员访问操作符. 后面在面向对象中会经常用到.
2. 使用 [ ] 按下标取数组元素. 需要注意, 下标从 0 开始计数
3. 使用 [ ] 操作既能读取数据, 也能修改数据.
4. 下标访问操作不能超出有效范围 [0, length - 1] , 如果超出有效范围, 会出现下标越界异常

代码示例: 下标越界

int[] arr = {
      1, 2, 3}; 
System.out.println(arr[100]); 
// 执行结果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100 
at Test.main(Test.java:4)

抛出了 java.lang.ArrayIndexOutOfBoundsException 异常. 使用数组一定要下标谨防越界.

代码示例: 遍历数组
所谓 “遍历” 是指将数组中的所有元素都访问一遍, 不重不漏. 通常需要搭配循环语句.

int[] arr = {
      1, 2, 3}; 
for (int i = 0; i < arr.length; i++) {
       
   System.out.println(arr[i]); 
}
// 执行结果 
1
2
3

代码示例: 使用 for-each 遍历数组

int[] arr = {
      1, 2, 3};
for (int x : arr) {
       
   System.out.println(x);
}
// 执行结果 
1
2
3

for-each 是 for 循环的另外一种使用方式. 能够更方便的完成对数组的遍历. 可以避免循环条件和更新语句写错.

数组作为方法的参数

基本用法

代码示例: 打印数组内容

public static void main(String[] args) {
      
      int[] arr = {
      1, 2, 3}; 
      printArray(arr); 
}

public static void printArray(int[] a) {
       
      for (int x : a) {
       
        System.out.println(x); 
      } 
}
// 执行结果 
1
2
3

在这个代码中

  • int[] a 是函数的形参, int[] arr 是函数实参.
  • 如果需要获取到数组长度, 同样可以使用 a.length

理解引用类型(敲黑板!!!)

我们知道Java是一门纯面向对象的语言,我们在使用Java语言编程时,到处都在使用对象(《Thinking in Java》一书中提到"Everything is object")
程序在运行时,对象是在堆内存(heap)中存储的,那么我们如何来访问对象呢?在C/C++中是通过指针,而Java中是通过引用,引用储存了对象在堆内存(heap)中的地址。

这里我们要先从内存开始说起.
如何理解内存?
内存就是指我们熟悉的 “内存”. 内存可以直观的理解成一个宿舍楼. 有一个长长的大走廊, 上面有很多房间.每个房间的大小是 1 Byte (如果计算机有 8G 内存, 则相当于有 80亿 个这样的房间).
每个房间上面又有一个门牌号, 这个门牌号就称为 地址

那么啥又是引用?
什么是引用?
引用相当于一个 “别名”, 也可以理解成一个指针.
创建一个引用只是相当于创建了一个很小的变量, 这个变量保存了一个整数, 这个整数表示内存中的一个地址.

请仔细看下图(引用其实和指针很像)
【Java】浅谈Java数组的定义与使用_第2张图片

引用与指针区别
(1)类型:
引用其值为地址的数据元素,Java封装了的地址,可以转换成字符串查看,长度也可以不必担心。
C指针是一个装地址的变量,长度一般是计算机字长,可以认为是个int。
(2)所占内存:
引用声明时没有实体,不占空间。
C指针如果声明之后会用到才会赋值。如果用不到不会分配内存。
(3)类型转换:
引用的类型转换,也可能不成功,运行时抛异常或者编译就不能通过。
C指针指示个内存地址,指向内存,对程序来说还都是一个地址,但可能所指的地址不是程序想要的。
(4)初始值:
引用初始值为java关键字null。
C指针是int,如不初始化指针,那它的值就不是固定的了,这很危险。
(5)计算:
引用不可以计算。
C指针是int,他可以计算,如++或–,所以经常用指针来代替数组下标。
(6)内存泄露:
Java引用不会产生内存泄露。
C指针是很容易产生内存泄露的,所以程序员要小心使用,及时回收。

认识null

null 在 Java 中表示 “空引用” , 也就是一个无效的引用.
null 的作用类似于 C 语言中的 NULL (空指针), 都是表示一个无效的内存位置. 因此不能对这个内存进行任何读写操作. 一旦尝试读写, 就会抛出 NullPointerException.

注意: Java 中并没有约定 null 和 0 号地址的内存有任何关联.

初时JVM内存区域划分(敲黑板!!!)

【Java】浅谈Java数组的定义与使用_第3张图片

  • 程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址.
  • 虚拟机栈(JVM Stack): 重点是存储局部变量表(当然也有其他信息). 我们刚才创建的 int[] arr 这样的存储地址的引用就是在这里保存.
  • 本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的.
  • 堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2, 3} )
  • 方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域.
  • 运行时常量池(Runtime Constant Pool): 是方法区的一部分, 存放字面量(字符串常量)与符号引用. (注意 从 JDK1.7 开始, 运行时常量池在堆上).

Native 本地方法:
JVM 是一个基于 C++ 实现的程序. 在 Java 程序执行过程中, 本质上也需要调用 C++ 提供的一些函数进行和操作系统底层进行一些交互. 因此在 Java 开发中也会调用到一些 C++ 实现的函数.
这里的 Native 方法就是指这些 C++ 实现的, 再由 Java 来调用的函数.

我们发现, 在上面的图中, 程序计数器, 虚拟机栈, 本地方法栈被很多个基佬紫的, 名叫 Thread(线程) 的方框圈起来了,并且存在很多份. 而 堆, 方法区, 运行时常量池, 只有一份.

重点理解 虚拟机栈 和 堆.
【Java】浅谈Java数组的定义与使用_第4张图片

  • 局部变量和引用保存在栈上, new 出的对象保存在堆上.
  • 堆的空间非常大, 栈的空间比较小.
  • 堆是整个 JVM 共享一个, 而栈每个线程具有一份(一个 Java 程序中可能存在多个栈).

数组作为方法的返回值

代码示例: 写一个方法, 将数组中的每个元素都 * 2

// 直接修改原数组 
class Test {
       
 public static void main(String[] args) {
      
  int[] arr = {
      1, 2, 3}; 
   transform(arr);
   printArray(arr); 
 }

 public static void printArray(int[] arr) {
       
   for (int i = 0; i < arr.length; i++) {
      
        System.out.println(arr[i]);
    } 
 }

 public static void transform(int[] arr) {
      
    for (int i = 0; i < arr.length; i++) {
      
        arr[i] = arr[i] * 2; 
    }
 }
}

这个代码固然可行, 但是破坏了原有数组. 有时候我们不希望破坏原数组, 就需要在方法内部创建一个新的数组, 并由方法返回出来.

// 返回一个新的数组 
class Test {
       
  public static void main(String[] args) {
      
      int[] arr = {
      1, 2, 3}; 
      int[] output = transform(arr);
      printArray(output); 
 }

 public static void printArray(int[] arr) {
      
     for (int i = 0; i < arr.length; i++) {
      
        System.out.println(arr[i]); 
    }
 }

 public static int[] transform(int[] arr) {
       
     int[] ret = new int[arr.length];
     for (int i = 0; i < arr.length; i++) {
       
        ret[i] = arr[i] * 2; 
     }
        return ret; 
     }
}

这样的话就不会破坏原有数组了.
另外由于数组是引用类型, 返回的时候只是将这个数组的首地址返回给函数调用者, 没有拷贝数组内容, 从而比较高效.

数组练习

二分查找

public class 二分查找 {
     
    public static int binarySearch(int []arr, int target) {
     
        int left = 0;
        int right = arr.length-1;
        while (left <= right) {
     
            int mid=(left+right)/2;
            if (arr[mid]<target){
     
                left = mid+1;
            }
            else if (arr[mid]>target){
     
                right = mid-1;
            }
            else
                return mid+1;
        }
        System.out.println("没有这个数");
        return -1;
    }

    public static void main(String[] args) {
     
        int target = 8;
        int arr[] = {
     1,2,3,4,5,6,7,8};
        System.out.println("要查找的数是第"+binarySearch(arr,target)+"个");
    }
}

冒泡排序

import java.util.Arrays;

public class 冒泡排序 {
     
    public static int[] bubble(int arr[]) {
     
        for (int i = 0; i < arr.length-1; i++){
     
            for (int j = 0; j < arr.length-1-i; j++){
     
                if (arr[j]>arr[j+1]) {
     
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        return arr;
    }
    public static void main(String[] args) {
     
        int arr [] = {
     1,1,4,7,2,4,6,9,2,6,5};
        System.out.println(Arrays.toString(bubble(arr)));
    }
}

判断数组是否有序

public class 判断数组是否有序 {
     
    public static boolean judgment(int arr[]) {
     
        for (int i = 0; (i+1)<arr.length; i++){
     
            if (arr[i]>arr[i+1])
                return false;
        }
        return true;
    }
    public static void main(String[] args) {
     
        int arr1[] = {
     1,2,3,4};
        int arr2[] = {
     2,1,4,3};
        if (judgment(arr1))
            System.out.println("arr1"+"有序");
        else
            System.out.println("arr1"+"无序");
        if (judgment(arr2))
            System.out.println("arr2"+"有序");
        else
            System.out.println("arr2"+"无序");
    }
}

只出现一次的元素

public class 只出现一次的数字 {
     
    public static int Only(int arr[]) {
     
         int tmp = 0;
         for (int i = 0; i < arr.length; i++) {
     
             /*
                涉及到异或运算,对于这道题,你应该了解异或有什么样性质
                1. 任何数与0异或,都为原数
                2. 与本身自己异或,则为0
                3. 交换律和结合律(解决这道题的关键),你把整个循环的计算写成数学运算过程,你会发现要利用交换律和结合律,可以实现这道题的要求
                 */
             tmp ^= arr[i];
         }
         return tmp;
    }
    public static void main(String[] args) {
     
        int arr[] = {
     2,0,0,1,1,2,6};
        System.out.println(Only(arr));
    }
}

改变原有数组的值

import java.util.*;

public class 改变原有数组元素的值 {
     
    public static int[] transform(int[]array2) {
     
        for (int i = 0; i < array2.length; i++) {
     
            array2[i] *=2;
        }
        return array2;
    }

    public static void main(String[] args) {
     
        int [] array1 = {
     1,2,3,};
        System.out.println(Arrays.toString(array1));

        System.out.println("×2改变之后数组="+ Arrays.toString(transform(array1)));
    }
}

数组所以元素之和

public class 数组所有元素之和 {
     
    public static float sum(int[]array) {
     
        int sum = 0;
        for (int i = 0; i < array.length; i++)
            sum += array[i];

        return sum;
    }

    public static void main(String[] args) {
     
        int [] array = {
     1,2,3,};
        for (int i = 0; i < array.length; i++)
            System.out.print(array[i]+" ");
        System.out.println();
        System.out.println("所以元素之和="+sum(array));
    }
}

数组拷贝

import java.util.Arrays;
public class 数组的拷贝 {
     
    public static  int[] copyOf(int []arr1) {
     
        int []arr2;
        arr2 = new int[arr1.length];
        for (int i = 0; i < arr1.length; i++) {
     
            arr2[i] = arr1[i];
        }
        return arr2;
    }
    public static void main(String[] args) {
     
        int []arr1={
     1,2,3,4,5};
        System.out.println("arr1="+Arrays.toString(arr1));
        System.out.println("arr2="+Arrays.toString(copyOf(arr1)));
    }
}

数组转字符串

public class 数组转字符串 {
     
    public static void printString(int[]arr) {
     
        String a ="[";
        for (int i = 0; i < arr.length; i++){
     
            a+=arr[i];
        if(i != arr.length -1)
            a += ",";
        }
        a+="]";
        System.out.println(a);
    }

    public static void main(String[] args) {
     
        int arr[] = {
     1,2,3,4,5};
        printString(arr);
    }
}

求数组元素平均值

public class 求数组的平均值 {
     
    public static float avg(int[]array) {
     
        float avg;
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
     
            sum += array[i];
        }
        avg = sum / array.length;

        return avg;
    }

    public static void main(String[] args) {
     
        int [] array = {
     1,2,3,};
        for (int i = 0; i < array.length; i++)
        System.out.print(array[i]+" ");
        System.out.println();
        System.out.println("平均数="+avg(array));
    }
}

二维数组

二维数组本质上也就是一维数组, 只不过每个元素又是一个一维数组.

基本语法

数据类型[][] 数组名称 = new 数据类型 [行数][列数] {
       初始化数据 };

代码示例
二维数组的用法和一维数组并没有明显差别, 因此我们不再赘述.
不过要注意一个点,C里每行数组会跟列对齐,会自动补0,java里不会自动补,如下代码

import java.util.Arrays;

public class test {
      
   public static void main(String[] args) {
      
       int[][] arr;
       arr = new int[][]{
       {
      1, 2, 3}, {
      5, 6, 7, 8}, {
      9, 10, 11, 12} };
       for (int row = 0; row < arr.length; row++) {
      
           for (int col = 0; col < arr[row].length; col++) {
      
               System.out.printf("%d\t", arr[row][col]);
           }
           System.out.println("");
       }// 执行结果
       // 1  2  3
       // 5  6  7  8
       // 9 10 11 12
   }
}


       ❤原创不易,如有错误,欢迎评论区留言指出,感激不尽❤
       ❤               如果觉得内容不错,给个三连不过分吧~        ❤
       ❤                            看到会回访~                                      ❤

你可能感兴趣的:(Java,笔记,1024程序员节,java,开发语言,后端)