【Java】数组的定义和使用(附管理系统实战案例)

Java 数组完全指南:从基础到实战

为什么需要数组?

假设要存储 5 个学生的 JavaSE 成绩,不用数组会怎样?

java 复制代码
public class TestStudent {
    public static void main(String[] args) {
        int score1 = 70;
        int score2 = 80;
        int score3 = 85;
        int score4 = 60;
        int score5 = 90;
        
        System.out.println(score1);
        System.out.println(score2);
        System.out.println(score3);
        System.out.println(score4);
        System.out.println(score5);
    }
}

这段代码有三个问题:

  • 学生数量一旦增加,变量数量就得同步增加------20 个学生要写 20 个变量,100 个学生要写 100 个
  • 这些成绩类型完全一样,却要反复声明变量
  • 无法批量处理,每个变量都得单独操作

数组就是为了解决这类问题。数组是相同类型元素的集合,在内存中占据一段连续空间。


一、数组的核心概念

1.1 数组的内存模型

数组在内存中有两个关键特征:

  1. 连续存储:所有元素在内存中紧挨着,没有间隙
  2. 编号访问:每个位置都有编号(下标),从 0 开始计数

1.2 如何创建数组

创建数组的基本格式:

java 复制代码
T[] 数组名 = new T[N];

这三个部分的含义:

  • T:元素类型,比如 int、double、String
  • T\[\]:数组类型,表示"T 类型的数组"
  • N:数组长度,能放几个元素

实际例子:

java 复制代码
int[] array1 = new int[10];        // 能放 10 个整数
double[] array2 = new double[5];   // 能放 5 个小数
String[] array3 = new String[3];   // 能放 3 个字符串

二、数组的初始化

初始化就是给数组填入初始数据。Java 提供了两种方式。

2.1 动态初始化

创建时只指定长度,不指定内容:

java 复制代码
int[] array = new int[10];

这时数组已经存在,每个位置都有默认值(int 类型默认是 0)。

2.2 静态初始化

创建时直接填入数据:

java 复制代码
int[] array1 = new int[]{0,1,2,3,4,5,6,7,8,9};
double[] array2 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};
String[] array3 = new String[]{"hello", "Java", "!!!"};

可以简写(省略 new T[]):

java 复制代码
int[] array1 = {1,2,3,4,5,6,7,8,9};
double[] array2 = {1.0, 2.0, 3.0, 4.0, 5.0};
String[] array3 = {"hello", "Java", "!!!"};

⚠️ 注意事项:

  1. 静态初始化时编译器会自动计算长度 ,不需要手动指定 [] 里的数字

  2. {} 中的数据类型必须一致,都要是声明的类型

  3. 简写形式只能在声明时使用,不能拆成两行:

java 复制代码
// ✅ 正确
int[] array = {1, 2, 3};

// ❌ 错误
int[] array;
array = {1, 2, 3};  // 编译失败
  1. 不推荐 C 风格写法:
java 复制代码
// 不推荐:容易让人误以为 arr 的类型是 int
int arr[] = {1, 2, 3};

// 推荐:类型清晰
int[] arr = {1, 2, 3};
  1. 动态和静态初始化都可以分两步,但简写不行:
java 复制代码
// ✅ 动态初始化可以分步
int[] array1;
array1 = new int[10];

// ✅ 静态初始化可以分步
int[] array2;
array2 = new int[]{10, 20, 30};

// ❌ 简写形式不能分步
int[] array3;
array3 = {1, 2, 3};  // 编译失败

2.3 数组的默认值

如果用动态初始化创建数组,每个位置会自动填入默认值:

类型 默认值
byte 0
short 0
int 0
long 0
float 0.0f
double 0
char ' '(空字符)
boolean false

引用类型(如 String)默认值是 null:

java 复制代码
String[] words = new String[3];
// words 的三个元素都是 null

三、数组的基本使用

3.1 访问数组元素

数组在内存中连续存储,每个位置都有编号(下标)。下标从 0 开始,依次递增。通过下标可以读取或修改任意位置的元素。

java 复制代码
int[] array = new int[]{10, 20, 30, 40, 50};
System.out.println(array[0]);  // 10
System.out.println(array[1]);  // 20
System.out.println(array[2]);  // 30
System.out.println(array[3]);  // 40
System.out.println(array[4]);  // 50

// 修改元素
array[0] = 100;
System.out.println(array[0]);  // 100

⚠️ 下标越界问题:

数组下标的有效范围是 [0, N-1],其中 N 是数组长度。访问范围之外的下标会抛出异常:

java 复制代码
int[] array = {1, 2, 3};
System.out.println(array[3]);  // 越界!数组只有 0、1、2 三个位置

// 运行结果
// Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3

3.2 遍历数组

遍历是指依次访问数组中的每一个元素。

最直接的方法是逐个打印:

java 复制代码
int[] array = new int[]{10, 20, 30, 40, 50};
System.out.println(array[0]);
System.out.println(array[1]);
System.out.println(array[2]);
System.out.println(array[3]);
System.out.println(array[4]);

但这样写有问题:

  • 数组增加一个元素,就得加一行代码
  • 100 个元素就要写 100 行
  • 修改操作(比如把打印改成加 1)也要改 100 行

既然操作都一样,就可以用循环。

方式一:用 for 循环

java 复制代码
int[] array = new int[]{10, 20, 30, 40, 50};
for(int i = 0; i < array.length; i++) {
    System.out.println(array[i]);
}

array.length 可以获取数组长度,这样就不用手动数有几个元素了。

方式二:用 for-each 循环

java 复制代码
int[] array = {1, 2, 3};
for (int x : array) {
    System.out.println(x);
}

for-each 是 for 循环的另一种写法,代码更简洁,也不容易写错循环条件。


四、数组是引用类型

4.1 JVM 内存分布

程序运行时,数据需要存储在内存中。JVM 把内存划分成不同区域:

JVM 内存主要分为 5 个区域:

1. 方法区(Method Area)

  • 存什么:类的信息、常量、静态变量
  • 白话:存放类的"设计图纸",比如类有哪些字段、哪些方法

2. 虚拟机栈(VM Stack)⭐ 重点

  • 存什么:方法里的局部变量
  • 白话:方法在执行时,把变量临时放这里。方法结束,变量就被清掉了
  • 举例:int a = 10; 这个 a 就在栈里

3. 本地方法栈(Native Stack)

  • 存什么:调用 C/C++ 代码时用的数据
  • 白话:Java 调用系统底层功能时用,日常开发很少接触

4. 堆(Heap)⭐ 重点

  • 存什么:new 出来的所有对象和数组
  • 白话:所有用 new 创建的东西都放这里,只要有引用指着就不会被清理
  • 举例:int[] arr = new int[10]; 这个数组就在堆里

5. 程序计数器(PC Register)

  • 存什么:记录代码执行到哪一行了
  • 白话:类似书签,记住下一步该执行哪条指令

4.2 基本类型 vs 引用类型

基本类型的变量直接存储值:

java 复制代码
int a = 10;

变量 a 里存的就是 10。

引用类型的变量存储的是地址:

java 复制代码
int[] array = new int[]{1,2,3};

变量 array 里存的不是数组本身,而是数组在堆中的地址。通过这个地址,才能找到真正的数组。

4.3 引用变量的赋值

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;  // 把 array2 中保存的数组地址赋给 array1
    array1[2] = 300;
    array1[3] = 400;
    array2[4] = 500;
    
    for (int i = 0; i < array2.length; i++) {
        System.out.println(array2[i]);
    }
}

执行 array1 = array2 后,array1 和 array2 都指向同一个数组。这时通过 array1 或 array2 修改数据,另一个也会看到变化。

这种赋值方式叫浅拷贝(或引用拷贝),只复制地址,不复制数组内容。

4.4 认识 null

null 表示"空引用",也就是不指向任何对象。

java 复制代码
int[] arr = null;
System.out.println(arr[0]);

// 运行结果
// Exception in thread "main" java.lang.NullPointerException

null 类似 C 语言的 NULL(空指针),表示无效的内存位置。不能对 null 进行读写操作,否则会抛出 NullPointerException。


五、数组的应用场景

5.1 保存数据

java 复制代码
public static void main(String[] args) {
    int[] array = {1, 2, 3};
    
    for(int i = 0; i < array.length; i++) {
        System.out.println(array[i] + " ");
    }
}

5.2 作为函数参数

基本类型作为参数

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

在 func 中修改 x,不会影响 num。

数组作为参数

java 复制代码
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

在 func 中修改数组,方法外的数组也会变化。

原因:数组是引用类型,传递的是地址,不是整个数组的拷贝。这样可以避免大数组的复制开销。

5.3 作为函数返回值

比如获取斐波那契数列的前 N 项:

java 复制代码
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]);
        }
    }
}

六、操作数组的工具类 Arrays

Java 提供了 java.util.Arrays 类,包含常用的数组操作方法。

6.1 数组转字符串

java 复制代码
import java.util.Arrays;

int[] arr = {1,2,3,4,5,6};
String newArr = Arrays.toString(arr);
System.out.println(newArr);

// 运行结果
// [1, 2, 3, 4, 5, 6]

打印数组变得更方便。

6.2 数组拷贝

java 复制代码
import java.util.Arrays;

public static void func() {
    // newArr 和 arr 指向同一个数组
    // newArr 修改后,arr 也会变
    int[] arr = {1,2,3,4,5,6};
    int[] newArr = arr;
    newArr[0] = 10;
    System.out.println("arr: " + Arrays.toString(arr));
    
    // 使用 copyOf 创建新数组
    // arr 和 newArr 是两个独立的数组
    arr[0] = 1;
    newArr = Arrays.copyOf(arr, arr.length);
    System.out.println("newArr: " + Arrays.toString(newArr));
    
    // 修改 arr 不会影响 newArr
    arr[0] = 10;
    System.out.println("arr: " + Arrays.toString(arr));
    System.out.println("newArr: " + Arrays.toString(newArr));
    
    // 拷贝指定范围
    int[] newArr2 = Arrays.copyOfRange(arr, 2, 4);
    System.out.println("newArr2: " + Arrays.toString(newArr2));
}

⚠️ 注意:如果数组存储的是引用类型,拷贝时需要考虑深浅拷贝问题(后续会详细介绍)。

自己实现拷贝:

java 复制代码
public static int[] copyOf(int[] arr) {
    int[] ret = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
        ret[i] = arr[i];
    }
    return ret;
}

6.3 查找元素(顺序查找)

在数组中查找指定元素,返回位置:

java 复制代码
public static void main(String[] args) {
    int[] arr = {1,2,3,10,5,6};
    System.out.println(find(arr, 10));
}

public static int find(int[] arr, int data) {
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == data) {
            return i;
        }
    }
    return -1;  // 没找到返回 -1
}

// 运行结果
// 3

6.4 查找元素(二分查找)

如果数组已经排序,可以用更快的二分查找。

什么是排序数组?

  • 升序:1 2 3 4,依次递增
  • 降序:4 3 2 1,依次递减

二分查找的思路:

  1. 取中间元素,与目标比较
  2. 如果相等,找到了
  3. 如果目标更小,去左半边继续查找
  4. 如果目标更大,去右半边继续查找
java 复制代码
public static void main(String[] args) {
    int[] arr = {1,2,3,4,5,6};
    System.out.println(binarySearch(arr, 6));
}

public static int binarySearch(int[] arr, int toFind) {
    int left = 0;
    int right = arr.length - 1;
    
    while (left <= right) {
        int mid = (left + right) / 2;
        if (toFind < arr[mid]) {
            right = mid - 1;  // 去左边找
        } else if (toFind > arr[mid]) {
            left = mid + 1;   // 去右边找
        } else {
            return mid;       // 找到了
        }
    }
    return -1;  // 没找到
}

// 运行结果
// 5

对于 10000 个元素的数组,二分查找最多只需要 14 次比较。数组越大,优势越明显。

6.5 数组排序(冒泡排序)

将数组按升序或降序排列。

算法思路(以升序为例):

  1. 从前往后比较相邻的两个元素
  2. 如果前面的比后面的大,就交换它们
  3. 这样一轮下来,最大的元素就到了最后
  4. 重复这个过程,直到所有元素都排好序
java 复制代码
public static void main(String[] args) {
    int[] arr = {9, 5, 2, 7};
    bubbleSort(arr);
    System.out.println(Arrays.toString(arr));
}

public static void bubbleSort(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = 1; j < arr.length-i; j++) {
            if (arr[j-1] > arr[j]) {
                int tmp = arr[j - 1];
                arr[j - 1] = arr[j];
                arr[j] = tmp;
            }
        }
    }
}

// 运行结果
// [2, 5, 7, 9]

冒泡排序比较慢。Java 内置了更高效的排序算法:

java 复制代码
public static void main(String[] args) {
    int[] arr = {9, 5, 2, 7};
    Arrays.sort(arr);
    System.out.println(Arrays.toString(arr));
}

6.6 数组逆序

将数组元素反转。

思路:

  1. 设置两个下标,一个指向开头,一个指向结尾
  2. 交换两个位置的元素
  3. 两个下标向中间移动,继续交换
  4. 直到它们相遇
java 复制代码
public static void main(String[] args) {
    int[] arr = {1, 2, 3, 4};
    reverse(arr);
    System.out.println(Arrays.toString(arr));
}

public static void reverse(int[] arr) {
    int left = 0;
    int right = arr.length - 1;
    
    while (left < right) {
        int tmp = arr[left];
        arr[left] = arr[right];
        arr[right] = tmp;
        left++;
        right--;
    }
}

七、二维数组

7.1 普通二维数组

二维数组本质是一维数组,只不过每个元素又是一个一维数组。

创建语法:

java 复制代码
数据类型[][] 数组名称 = new 数据类型[行数][列数] { 初始化数据 };

行数不能省略,列数可以省略。

示例:

java 复制代码
int[][] arr = {
    {1, 2, 3, 4},
    {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    4
// 5    6    7    8
// 9    10   11   12

理解二维数组:

  • arr.length 是行数
  • arr[row].length 是第 row 行的列数
  • 每一行是独立的一维数组

7.2 不规则的二维数组

二维数组的每一行长度可以不同:

java 复制代码
int[][] array = new int[2][];
array[0] = new int[3];  // 第 1 行有 3 列
array[1] = new int[5];  // 第 2 行有 5 列

这就是不规则的二维数组。


八、实战案例:学生成绩管理系统

综合运用数组的各种操作。

需求:

  1. 录入学生成绩
  2. 计算平均分
  3. 查找最高分和最低分
  4. 按成绩降序排列
  5. 查询指定学生成绩
java 复制代码
import java.util.Arrays;
import java.util.Scanner;

public class StudentScoreManager {
    
    // 学生姓名数组
    private static String[] names;
    // 学生成绩数组
    private static int[] scores;
    // 当前学生数量
    private static int count = 0;
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.print("请输入班级学生人数:");
        int capacity = scanner.nextInt();
        names = new String[capacity];
        scores = new int[capacity];
        
        while (true) {
            printMenu();
            System.out.print("请选择操作:");
            int choice = scanner.nextInt();
            
            switch (choice) {
                case 1:
                    inputScores(scanner);
                    break;
                case 2:
                    calculateAverage();
                    break;
                case 3:
                    findMaxMin();
                    break;
                case 4:
                    sortByScore();
                    break;
                case 5:
                    searchStudent(scanner);
                    break;
                case 6:
                    displayAllScores();
                    break;
                case 0:
                    System.out.println("感谢使用,再见!");
                    return;
                default:
                    System.out.println("无效选择,请重新输入");
            }
        }
    }
    
    // 打印菜单
    private static void printMenu() {
        System.out.println("\n========== 学生成绩管理系统 ==========");
        System.out.println("1. 录入学生成绩");
        System.out.println("2. 计算平均分");
        System.out.println("3. 查找最高分和最低分");
        System.out.println("4. 按成绩降序排列");
        System.out.println("5. 查询指定学生成绩");
        System.out.println("6. 显示所有学生成绩");
        System.out.println("0. 退出系统");
        System.out.println("=====================================");
    }
    
    // 1. 录入学生成绩
    private static void inputScores(Scanner scanner) {
        if (count >= names.length) {
            System.out.println("学生人数已满,无法继续录入!");
            return;
        }
        
        System.out.print("请输入学生姓名:");
        String name = scanner.next();
        System.out.print("请输入学生成绩(0-100):");
        int score = scanner.nextInt();
        
        if (score < 0 || score > 100) {
            System.out.println("成绩无效,请输入 0-100 之间的分数");
            return;
        }
        
        names[count] = name;
        scores[count] = score;
        count++;
        System.out.println("录入成功!");
    }
    
    // 2. 计算平均分
    private static void calculateAverage() {
        if (count == 0) {
            System.out.println("暂无学生数据!");
            return;
        }
        
        int sum = 0;
        for (int i = 0; i < count; i++) {
            sum += scores[i];
        }
        double average = (double) sum / count;
        System.out.printf("班级平均分:%.2f\n", average);
    }
    
    // 3. 查找最高分和最低分
    private static void findMaxMin() {
        if (count == 0) {
            System.out.println("暂无学生数据!");
            return;
        }
        
        int maxScore = scores[0];
        int minScore = scores[0];
        String maxName = names[0];
        String minName = names[0];
        
        for (int i = 1; i < count; i++) {
            if (scores[i] > maxScore) {
                maxScore = scores[i];
                maxName = names[i];
            }
            if (scores[i] < minScore) {
                minScore = scores[i];
                minName = names[i];
            }
        }
        
        System.out.println("最高分:" + maxName + " - " + maxScore + "分");
        System.out.println("最低分:" + minName + " - " + minScore + "分");
    }
    
    // 4. 按成绩降序排列
    private static void sortByScore() {
        if (count == 0) {
            System.out.println("暂无学生数据!");
            return;
        }
        
        // 冒泡排序(降序)
        for (int i = 0; i < count - 1; i++) {
            for (int j = 0; j < count - 1 - i; j++) {
                if (scores[j] < scores[j + 1]) {
                    // 交换成绩
                    int tempScore = scores[j];
                    scores[j] = scores[j + 1];
                    scores[j + 1] = tempScore;
                    
                    // 交换姓名
                    String tempName = names[j];
                    names[j] = names[j + 1];
                    names[j + 1] = tempName;
                }
            }
        }
        
        System.out.println("排序完成!");
        displayAllScores();
    }
    
    // 5. 查询指定学生成绩
    private static void searchStudent(Scanner scanner) {
        if (count == 0) {
            System.out.println("暂无学生数据!");
            return;
        }
        
        System.out.print("请输入要查询的学生姓名:");
        String name = scanner.next();
        
        for (int i = 0; i < count; i++) {
            if (names[i].equals(name)) {
                System.out.println("学生:" + names[i] + ",成绩:" + scores[i] + "分");
                return;
            }
        }
        
        System.out.println("未找到该学生!");
    }
    
    // 6. 显示所有学生成绩
    private static void displayAllScores() {
        if (count == 0) {
            System.out.println("暂无学生数据!");
            return;
        }
        
        System.out.println("\n========== 学生成绩列表 ==========");
        System.out.println("序号\t姓名\t\t成绩");
        System.out.println("----------------------------------");
        for (int i = 0; i < count; i++) {
            System.out.printf("%d\t%s\t\t%d\n", i + 1, names[i], scores[i]);
        }
        System.out.println("==================================\n");
    }
}

运行示例:

复制代码
请输入班级学生人数:5

========== 学生成绩管理系统 ==========
1. 录入学生成绩
2. 计算平均分
3. 查找最高分和最低分
4. 按成绩降序排列
5. 查询指定学生成绩
6. 显示所有学生成绩
0. 退出系统
=====================================
请选择操作:1
请输入学生姓名:张三
请输入学生成绩(0-100):85
录入成功!

请选择操作:1
请输入学生姓名:李四
请输入学生成绩(0-100):92
录入成功!

请选择操作:2
班级平均分:88.50

请选择操作:3
最高分:李四 - 92分
最低分:张三 - 85分

九、常见问题与注意事项

9.1 数组下标越界

java 复制代码
int[] arr = {1, 2, 3};
System.out.println(arr[3]);  // ArrayIndexOutOfBoundsException

原因:数组下标范围是 0, length-1,arr3 超出范围

解决 :使用 arr.length 动态获取长度,确保下标在有效范围内

9.2 空指针异常

java 复制代码
int[] arr = null;
System.out.println(arr[0]);  // NullPointerException

原因:数组引用是 null,没有指向任何对象

解决:使用前先检查:

java 复制代码
if (arr != null && arr.length > 0) {
    System.out.println(arr[0]);
}

9.3 浅拷贝 vs 深拷贝

java 复制代码
// 浅拷贝:只复制引用
int[] arr1 = {1, 2, 3};
int[] arr2 = arr1;  // arr1 和 arr2 指向同一个数组
arr2[0] = 100;
System.out.println(arr1[0]);  // 输出 100

// 深拷贝:创建新数组
int[] arr3 = Arrays.copyOf(arr1, arr1.length);
arr3[0] = 200;
System.out.println(arr1[0]);  // 输出 100

9.4 数组长度固定

数组创建后长度不能改变。如果需要动态扩容,应该使用 ArrayList(后续课程介绍)。

java 复制代码
int[] arr = new int[3];
// 无法直接扩展到 5 个元素,只能创建新数组并拷贝
int[] newArr = new int[5];
for (int i = 0; i < arr.length; i++) {
    newArr[i] = arr[i];
}

十、总结

数组的本质

  • 相同类型元素的集合
  • 在内存中占据连续空间
  • 通过下标快速访问(时间复杂度 O(1))

数组的优缺点

✅ 优点:

  1. 访问速度快,支持随机访问
  2. 内存连续,缓存友好
  3. 实现简单,适合固定数量的数据

❌ 缺点:

  1. 长度固定,无法动态扩容
  2. 插入删除效率低(需要移动元素)
  3. 创建时必须指定大小

关键要点

  1. 数组下标从 0 开始,范围是 0, length-1
  2. 数组是引用类型,存储在堆中
  3. 使用 Arrays 工具类可以简化操作
  4. 注意避免下标越界和空指针异常
  5. 理解浅拷贝和深拷贝的区别

进阶方向

  • 学习 ArrayList 等动态数据结构
  • 掌握各种排序算法(快排、归并等)
  • 了解二维数组在图形、矩阵中的应用
  • 深入理解 JVM 内存管理机制

数组是编程基础中的基础。掌握数组操作对后续学习至关重要。继续练习,在实际项目中灵活运用!


参考资料:

相关推荐
橙子圆1232 小时前
JUC之集合类不安全
java·开发语言
阿里嘎多学长2 小时前
2026-09-29 GitHub 热点项目精选
开发语言·程序员·github·代码托管
Bruce_Liuxiaowei2 小时前
网页版 DeepSeek “harness desktop“ WebGL 上下文创建失败排查实录
开发语言·javascript·webgl
狗凯之家源码网2 小时前
PHP 用户反馈系统源码深度评测与实战指南
开发语言·php·用户反馈系统
谢亮_vipxieliang2 小时前
Stream API 不是银弹:常见坑与性能建议
java·开发语言
迅猛龙办公室3 小时前
实现第一个python程序(HelloWorld)
开发语言·python
源码宝3 小时前
Web‑PACS 云影像源码|Java+Vue3 医院影像管理系统完整方案
java·源码·影像pacs·成品源码·医院影像系统
phltxy3 小时前
C 语言动态内存管理:从申请空间到安全释放
c语言·开发语言·ui
可乐鸡翅yeah_3 小时前
M3U8 防盗链 URL‑Token 签名,新手开发实操避坑
开发语言·javascript·ios·音视频·safari