Java 入门(IDEA 高效调试 与 数组)

目录

一、先搞懂:什么是程序调试?

[二、IDEA 调试](#二、IDEA 调试)

[1. 调试三步基础](#1. 调试三步基础)

[2. 核心调试操作](#2. 核心调试操作)

[3. 进阶:条件断点](#3. 进阶:条件断点)

[4. 调试面板看什么?](#4. 调试面板看什么?)

[三、Java 数组](#三、Java 数组)

[1. 为什么要用数组?](#1. 为什么要用数组?)

[2. 数组创建与初始化(两种方式)](#2. 数组创建与初始化(两种方式))

动态初始化(指定长度)

静态初始化(指定内容)

[3. 数组遍历:3 种写法](#3. 数组遍历:3 种写法)

[4. 关键:数组是引用类型](#4. 关键:数组是引用类型)

[5. 数组作为方法参数 / 返回值](#5. 数组作为方法参数 / 返回值)

[6. 数组常用工具方法(java.util.Arrays)](#6. 数组常用工具方法(java.util.Arrays))

[7. 经典算法手写(面试常考)](#7. 经典算法手写(面试常考))

[8. 二维数组](#8. 二维数组)

[四、调试 + 数组:实战组合技巧](#四、调试 + 数组:实战组合技巧)

五、总结


作为 Java 开发者,调试能力决定排错效率,数组功底决定代码质量。这篇文章把 IDEA 调试全套技巧、数组从基础到进阶的知识点一次性讲透,适合新手夯实基础、老手快速回顾。


一、先搞懂:什么是程序调试?

调试(Debugging)不是简单 "改代码",而是定位问题 → 缩小范围 → 修复验证的完整过程。

  • 小代码:肉眼读 + 打印日志
  • 复杂项目:必须用 IDE 调试器

IDEA 内置的调试器是 Java 开发效率神器,掌握它能让你快速揪出隐藏 Bug。


二、IDEA 调试

1. 调试三步基础

  1. 打断点:代码行号左侧单击,出现红色圆点
  2. 启动调试:右键 → Debug
  3. 控制执行:用快捷键一步步观察变量与流程

2. 核心调试操作

操作 快捷键 作用
逐过程(不进方法) F8 一行一行走,跳过方法内部
逐语句(进入方法) F7 进入自定义方法内部
强制进入 Alt+Shift+F7 强行进入 JDK 库方法 / 无源码方法
跳出方法 Shift+F8 执行完当前方法并返回调用处
运行到光标 Alt+F9 直接跳到光标所在行
恢复程序 F9 跳到下一个断点 / 结束
重新调试 Ctrl+F5 重启调试会话
停止调试 Ctrl+F2 终止调试
查看所有断点 Ctrl+Shift+F8 统一管理断点

3. 进阶:条件断点

循环几百次只想在特定值停下?用条件断点

  1. 右键断点
  2. 填入条件(如 i == 20
  3. 调试只会在条件成立时暂停

4. 调试面板看什么?

  • Debugger 面板:调用栈 + 实时变量值 + 表达式计算
  • Console 面板:程序正常输出 / 异常信息
  • Mute Breakpoints:一键临时屏蔽所有断点

三、Java 数组

数组是 Java 最基础的数据结构,相同类型、连续内存、下标从 0 开始,这三个特征刻在心里。

1. 为什么要用数组?

不用数组:存 100 个成绩要定义 100 个变量。用数组:一行搞定,遍历、修改、传参都更简洁。

2. 数组创建与初始化(两种方式)

动态初始化(指定长度)
java 复制代码
int[] arr = new int[5]; // 默认值:0
String[] strs = new String[3]; // 默认值:null
静态初始化(指定内容)
java 复制代码
// 完整写法
int[] arr1 = new int[]{1,2,3,4,5};
// 简写(推荐)
int[] arr2 = {1,2,3,4,5};

⚠️ 注意:

  • 简写形式不能拆分两行写
  • 下标范围:[0, length),越界抛 ArrayIndexOutOfBoundsException

3. 数组遍历:3 种写法

  1. 普通 for 循环(可修改元素)
java 复制代码
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}
  1. for-each 循环(只读更简洁)
java 复制代码
for (int num : arr) {
    System.out.println(num);
}
  1. Arrays.toString(快速打印)
javascript 复制代码
System.out.println(Arrays.toString(arr));

4. 关键:数组是引用类型

  • 基本类型:变量存
  • 引用类型:变量存堆内存地址
  • arr1 = arr2指向同一块内存,不是拷贝
java 复制代码
int[] a = {1,2,3};
int[] b = a;
b[0] = 100; // a[0] 也会变成 100
  • null:空引用,访问会抛 NullPointerException

5. 数组作为方法参数 / 返回值

  • 传基本类型:值传递,不影响原变量
  • 传数组:引用传递,方法内修改会影响原数组
  • 数组可直接作为返回值,返回一组数据

6. 数组常用工具方法(java.util.Arrays)

  • Arrays.toString(arr):数组转字符串
java 复制代码
import java.util.Arrays;

/**
 * Arrays.toString():数组转字符串
 * 特点:
 * 1. 一维数组直接输出易读格式
 * 2. 多维数组需用 Arrays.deepToString()
 * 3. 空数组输出 []
 */
public class ArraysToStringDemo {
    public static void main(String[] args) {
        // 测试1:普通int数组
        int[] intArr = {1, 2, 3, 4, 5};
        System.out.println("int数组转字符串:" + Arrays.toString(intArr));

        // 测试2:字符串数组
        String[] strArr = {"Java", "数组", "工具类"};
        System.out.println("字符串数组转字符串:" + Arrays.toString(strArr));

        // 测试3:空数组
        int[] emptyArr = new int[0];
        System.out.println("空数组转字符串:" + Arrays.toString(emptyArr));

        // 测试4:多维数组(注意:一维toString不适用,需用deepToString)
        int[][] multiArr = {{1,2}, {3,4}};
        System.out.println("多维数组用toString:" + Arrays.toString(multiArr)); // 输出地址
        System.out.println("多维数组用deepToString:" + Arrays.deepToString(multiArr)); // 正确输出
    }
}


/*结果:
int数组转字符串:[1, 2, 3, 4, 5]
字符串数组转字符串:[Java, 数组, 工具类]
空数组转字符串:[]
多维数组用toString:[[I@7852e922, [I@4e25154f]
多维数组用deepToString:[[1, 2], [3, 4]]
*/
  • Arrays.copyOf(arr, len):数组拷贝(新对象)
java 复制代码
import java.util.Arrays;

/**
 * Arrays.copyOf():数组拷贝
 * 特点:
 * 1. 返回新数组,原数组不受影响(深拷贝)
 * 2. len < 原长度:截取前len个元素
 * 3. len > 原长度:补默认值(int补0,String补null)
 */
public class ArraysCopyOfDemo {
    public static void main(String[] args) {
        int[] originalArr = {10, 20, 30, 40, 50};
        System.out.println("原数组:" + Arrays.toString(originalArr));

        // 场景1:拷贝长度 = 原长度(完整拷贝)
        int[] copyFull = Arrays.copyOf(originalArr, originalArr.length);
        System.out.println("完整拷贝:" + Arrays.toString(copyFull));

        // 场景2:拷贝长度 < 原长度(截取)
        int[] copyShort = Arrays.copyOf(originalArr, 3);
        System.out.println("截取前3个元素:" + Arrays.toString(copyShort));

        // 场景3:拷贝长度 > 原长度(补默认值)
        int[] copyLong = Arrays.copyOf(originalArr, 7);
        System.out.println("补0到7个元素:" + Arrays.toString(copyLong));

        // 验证:修改新数组,原数组不变
        copyFull[0] = 999;
        System.out.println("修改后新数组:" + Arrays.toString(copyFull));
        System.out.println("原数组仍不变:" + Arrays.toString(originalArr));
    }
}

/*结果:
原数组:[10, 20, 30, 40, 50]
完整拷贝:[10, 20, 30, 40, 50]
截取前3个元素:[10, 20, 30]
补0到7个元素:[10, 20, 30, 40, 50, 0, 0]
修改后新数组:[999, 20, 30, 40, 50]
原数组仍不变:[10, 20, 30, 40, 50]
*/
  • Arrays.copyOfRange(arr, from, to):范围拷贝
java 复制代码
import java.util.Arrays;

/**
 * Arrays.copyOfRange():范围拷贝
 * 特点:
 * 1. 左闭右开:[from, to)
 * 2. from = 0 且 to = 原长度 → 等价于 copyOf
 * 3. 下标越界会抛 ArrayIndexOutOfBoundsException
 */
public class ArraysCopyOfRangeDemo {
    public static void main(String[] args) {
        String[] originalArr = {"A", "B", "C", "D", "E", "F"};
        System.out.println("原数组:" + Arrays.toString(originalArr));

        // 场景1:拷贝中间范围(下标1到4,包含1,不包含4)
        String[] range1 = Arrays.copyOfRange(originalArr, 1, 4);
        System.out.println("拷贝[1,4):" + Arrays.toString(range1)); // [B, C, D]

        // 场景2:拷贝从0到末尾(完整拷贝)
        String[] range2 = Arrays.copyOfRange(originalArr, 0, originalArr.length);
        System.out.println("拷贝完整数组:" + Arrays.toString(range2));

        // 场景3:拷贝到超出原长度(补默认值null)
        String[] range3 = Arrays.copyOfRange(originalArr, 3, 8);
        System.out.println("拷贝[3,8)(补null):" + Arrays.toString(range3));
    }
}

/*结果:
原数组:[A, B, C, D, E, F]
拷贝[1,4):[B, C, D]
拷贝完整数组:[A, B, C, D, E, F]
拷贝[3,8)(补null):[D, E, F, null, null]
*/
  • Arrays.sort(arr):高效排序
java 复制代码
import java.util.Arrays;

/**
 * Arrays.sort():数组排序
 * 特点:
 * 1. 基本类型数组:快速排序/双轴快排,效率高
 * 2. 直接修改原数组(原地排序)
 * 3. 字符串数组:按Unicode编码升序(字母A-Z对应升序)
 */
public class ArraysSortDemo {
    public static void main(String[] args) {
        // 场景1:int数组升序排序
        int[] intArr = {5, 2, 9, 1, 5, 6};
        System.out.println("排序前int数组:" + Arrays.toString(intArr));
        Arrays.sort(intArr);
        System.out.println("排序后int数组:" + Arrays.toString(intArr));

        // 场景2:字符串数组排序
        String[] strArr = {"Java", "Python", "C", "JavaScript"};
        System.out.println("\n排序前字符串数组:" + Arrays.toString(strArr));
        Arrays.sort(strArr);
        System.out.println("排序后字符串数组:" + Arrays.toString(strArr));

        // 场景3:指定范围排序(sort(arr, from, to):左闭右开)
        int[] rangeArr = {10, 5, 8, 2, 7, 1};
        System.out.println("\n排序前范围数组:" + Arrays.toString(rangeArr));
        Arrays.sort(rangeArr, 1, 5); // 只排序下标1到4的元素
        System.out.println("排序[1,5)后:" + Arrays.toString(rangeArr));
    }
}

/*结果:
排序前int数组:[5, 2, 9, 1, 5, 6]
排序后int数组:[1, 2, 5, 5, 6, 9]

排序前字符串数组:[Java, Python, C, JavaScript]
排序后字符串数组:[C, Java, JavaScript, Python]

排序前范围数组:[10, 5, 8, 2, 7, 1]
排序[1,5)后:[10, 2, 5, 7, 8, 1]
*/
  • Arrays.binarySearch(arr, key):有序数组二分查找
java 复制代码
import java.util.Arrays;

/**
 * Arrays.binarySearch():二分查找
 * 前提:数组必须是升序排序后的!
 * 特点:
 * 1. 找到:返回元素下标
 * 2. 未找到:返回 -(插入点) - 1
 * 3. 有重复元素:返回任意一个匹配下标(不保证是第一个)
 */
public class ArraysBinarySearchDemo {
    public static void main(String[] args) {
        int[] sortedArr = {1, 2, 3, 5, 7, 9, 10}; // 必须先排序!
        System.out.println("有序数组:" + Arrays.toString(sortedArr));

        // 场景1:查找存在的元素
        int key1 = 7;
        int index1 = Arrays.binarySearch(sortedArr, key1);
        System.out.println("查找" + key1 + ":下标=" + index1);

        // 场景2:查找不存在的元素
        int key2 = 4;
        int index2 = Arrays.binarySearch(sortedArr, key2);
        System.out.println("查找" + key2 + ":返回值=" + index2 + "(插入点是3,-(3)-1=-4)");

        // 场景3:查找超出范围的元素
        int key3 = 11;
        int index3 = Arrays.binarySearch(sortedArr, key3);
        System.out.println("查找" + key3 + ":返回值=" + index3 + "(插入点是7,-(7)-1=-8)");

        // 错误示例:未排序数组查找(结果不可靠)
        int[] unsortedArr = {5, 2, 9};
        int index4 = Arrays.binarySearch(unsortedArr, 2);
        System.out.println("\n未排序数组查找2:" + index4 + "(结果错误,不可信)");
    }
}

/*结果:
有序数组:[1, 2, 3, 5, 7, 9, 10]
查找7:下标=4
查找4:返回值=-4(插入点是3,-(3)-1=-4)
查找11:返回值=-8(插入点是7,-(7)-1=-8)

未排序数组查找2:-1(结果错误,不可信)
*/

7. 经典算法手写(面试常考)

  • 顺序查找
java 复制代码
/**
 * 顺序查找(线性查找)
 * 核心:逐个遍历、逐一比较,找到返回下标,未找到返回-1
 * 适用:无序/有序数组都能查,优点是简单,缺点是效率低(时间复杂度 O(n))
 */
public class SequentialSearch {
    public static void main(String[] args) {
        // 测试数组(无序也能查)
        int[] arr = {8, 3, 9, 7, 2, 5, 1, 6, 4};
        int target = 7;
        
        // 调用查找方法
        int index = sequentialSearch(arr, target);
        
        // 输出结果
        if (index != -1) {
            System.out.println("找到目标值 " + target + ",下标为:" + index);
        } else {
            System.out.println("未找到目标值 " + target);
        }
    }

    /**
     * 顺序查找核心方法
     * @param arr 待查找的数组
     * @param target 要找的目标值
     * @return 找到返回下标,未找到返回-1
     */
    public static int sequentialSearch(int[] arr, int target) {
        // 健壮性处理:数组为空/长度为0,直接返回-1
        if (arr == null || arr.length == 0) {
            return -1;
        }
        
        // 遍历数组,逐个比较
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == target) {
                return i; // 找到立即返回下标,无需继续遍历
            }
        }
        
        // 遍历完都没找到,返回-1
        return -1;
    }
}
  • 二分查找(有序数组)
java 复制代码
/**
 * 二分查找(折半查找)
 * 核心:利用有序数组特性,每次排除一半元素,效率高(时间复杂度 O(log₂n))
 * 前提:数组必须是有序的(升序/降序,代码需对应调整)
 */
public class BinarySearch {
    public static void main(String[] args) {
        // 测试数组(必须是有序数组,这里用升序)
        int[] sortedArr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        int target = 5;
        
        // 调用二分查找方法
        int index = binarySearch(sortedArr, target);
        
        // 输出结果
        if (index != -1) {
            System.out.println("找到目标值 " + target + ",下标为:" + index);
        } else {
            System.out.println("未找到目标值 " + target);
        }
    }

    /**
     * 二分查找核心方法(升序数组)
     * @param sortedArr 有序数组(升序)
     * @param target 要找的目标值
     * @return 找到返回下标,未找到返回-1
     */
    public static int binarySearch(int[] sortedArr, int target) {
        // 健壮性处理
        if (sortedArr == null || sortedArr.length == 0) {
            return -1;
        }
        
        // 定义左右指针
        int left = 0;
        int right = sortedArr.length - 1;
        
        // 循环条件:左指针 <= 右指针(注意是 <=,否则会漏查最后一个元素)
        while (left <= right) {
            // 计算中间下标(避免溢出:等价于 (left + right) / 2,但更安全)
            int mid = left + (right - left) / 2;
            
            if (sortedArr[mid] == target) {
                return mid; // 找到目标,返回下标
            } else if (sortedArr[mid] < target) {
                // 目标在右半部分,左指针右移
                left = mid + 1;
            } else {
                // 目标在左半部分,右指针左移
                right = mid - 1;
            }
        }
        
        // 循环结束仍未找到,返回-1
        return -1;
    }
}
  • 冒泡排序

    java 复制代码
    /**
     * 冒泡排序
     * 核心:相邻元素两两比较,大的元素逐步"冒泡"到数组末尾
     * 优化:如果某一轮没有交换,说明数组已有序,直接退出(减少循环次数)
     * 时间复杂度:最坏 O(n²),最好 O(n)(已排序数组)
     */
    public class BubbleSort {
        public static void main(String[] args) {
            // 测试数组
            int[] arr = {8, 3, 9, 7, 2, 5, 1, 6, 4};
            System.out.println("排序前:" + Arrays.toString(arr));
            
            // 调用冒泡排序方法
            bubbleSort(arr);
            
            // 输出结果
            System.out.println("排序后:" + Arrays.toString(arr));
        }
    
        /**
         * 冒泡排序核心方法(升序)
         * @param arr 待排序的数组(直接修改原数组)
         */
        public static void bubbleSort(int[] arr) {
            // 健壮性处理
            if (arr == null || arr.length <= 1) {
                return; // 空数组/只有1个元素,无需排序
            }
            
            int length = arr.length;
            
            // 外层循环:控制排序轮数(最多 length-1 轮)
            for (int i = 0; i < length - 1; i++) {
                // 标记:本轮是否发生交换
                boolean swapped = false;
                
                // 内层循环:每轮比较到 length-1-i 位置(后i个元素已排好序)
                for (int j = 0; j < length - 1 - i; j++) {
                    // 相邻元素比较,前 > 后则交换(升序)
                    if (arr[j] > arr[j + 1]) {
                        // 交换两个元素
                        int temp = arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = temp;
                        
                        // 标记发生了交换
                        swapped = true;
                    }
                }
                
                // 优化:本轮无交换,说明数组已有序,直接退出循环
                if (!swapped) {
                    break;
                }
            }
        }
    }
  • 数组逆序

java 复制代码
/**
 * 数组逆序
 * 核心:双指针法,首尾元素交换,直到指针相遇
 * 优点:时间复杂度 O(n),空间复杂度 O(1)(原地逆序,不额外占用空间)
 */
public class ReverseArray {
    public static void main(String[] args) {
        // 测试数组
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        System.out.println("逆序前:" + Arrays.toString(arr));
        
        // 调用逆序方法
        reverseArray(arr);
        
        // 输出结果
        System.out.println("逆序后:" + Arrays.toString(arr));
    }

    /**
     * 数组逆序核心方法(原地逆序,直接修改原数组)
     * @param arr 待逆序的数组
     */
    public static void reverseArray(int[] arr) {
        // 健壮性处理
        if (arr == null || arr.length <= 1) {
            return; // 空数组/只有1个元素,无需逆序
        }
        
        // 定义首尾指针
        int left = 0;
        int right = arr.length - 1;
        
        // 循环交换:左指针 < 右指针时交换
        while (left < right) {
            // 交换首尾元素
            int temp = arr[left];
            arr[left] = arr[right];
            arr[right] = temp;
            
            // 左指针右移,右指针左移
            left++;
            right--;
        }
    }
}
  • 自定义数组拷贝
java 复制代码
/**
 * 自定义数组拷贝
 * 核心:创建新数组,遍历原数组,逐个复制元素到新数组
 * 对比 JDK 自带的 Arrays.copyOf:逻辑一致,帮你理解底层原理
 */
public class CustomArrayCopy {
    public static void main(String[] args) {
        // 测试数组
        int[] originalArr = {8, 3, 9, 7, 2, 5, 1, 6, 4};
        System.out.println("原数组:" + Arrays.toString(originalArr));
        
        // 调用自定义拷贝方法
        int[] copyArr = customCopyOf(originalArr, originalArr.length);
        System.out.println("拷贝数组:" + Arrays.toString(copyArr));
        
        // 验证:修改拷贝数组,原数组不受影响(证明是深拷贝)
        copyArr[0] = 100;
        System.out.println("修改后拷贝数组:" + Arrays.toString(copyArr));
        System.out.println("修改后原数组:" + Arrays.toString(originalArr));
    }

    /**
     * 自定义数组拷贝方法
     * @param original 原数组
     * @param newLength 新数组长度(可大于/小于原数组长度)
     * @return 新的拷贝数组
     */
    public static int[] customCopyOf(int[] original, int newLength) {
        // 健壮性处理:原数组为空
        if (original == null) {
            return null;
        }
        
        // 1. 创建新数组(指定长度)
        int[] newArr = new int[newLength];
        
        // 2. 确定要拷贝的元素个数(取原数组长度和新长度的较小值)
        int copyLength = Math.min(original.length, newLength);
        
        // 3. 遍历原数组,逐个复制到新数组
        for (int i = 0; i < copyLength; i++) {
            newArr[i] = original[i];
        }
        
        // 4. 返回新数组(如果新长度 > 原长度,多余位置默认值为0)
        return newArr;
    }
}

8. 二维数组

本质:数组的数组

java 复制代码
int[][] arr = {{1,2},{3,4},{5,6}};
// 遍历
for (int i = 0; i < arr.length; i++) {
    for (int j = 0; j < arr[i].length; j++) {
        System.out.print(arr[i][j] + " ");
    }
    System.out.println();
}

四、调试 + 数组:实战组合技巧

  1. 遍历数组时用条件断点,只看目标元素
  2. 调试面板直接查看数组每一位的值
  3. 下标越界时,用调试看循环边界是否正确
  4. 引用传递问题:在面板看地址是否相同

五、总结

  • 调试是程序员的基本功,IDEA 快捷键用熟效率翻倍
  • 数组是数据结构基石,连续内存、引用类型、下标 0 起步
  • 先会调试排错,再扎实掌握数组,Java 基础才算稳

把这篇收藏好,写代码、查 Bug、面试复习都能用得上。

相关推荐
东离与糖宝2 小时前
315警示:AI接口被恶意调用?Java高并发+限流+鉴权防护实战
java·人工智能
火山上的企鹅2 小时前
Qt/QGroundControl 实战:接入 Skydroid(云卓) G20 遥控器 Android SDK 并实时显示摇杆与信号质量
android·开发语言·qt·qgroundcontrol·云卓sdk
YmaxU2 小时前
SpringAIAlibaba学习使用 ---Graph
java·学习·spring·ai
曾阿伦2 小时前
Python项目管理从Poetry迁移到uv:极速体验与实操指南
开发语言·python·uv
StackNoOverflow2 小时前
Spring整合MyBatis与事务管理详解(第三部分)
java·spring
2401_891482172 小时前
C++中的观察者模式
开发语言·c++·算法
没有bug.的程序员2 小时前
500个微服务上云全线假死:Spring Boot 3.2 自动配置底层的生死狙击
java·spring boot·微服务·kubernetes·自动配置
sinat_255487812 小时前
保存 Object 数组
java·服务器·前端
AnalogElectronic2 小时前
windows文件加解密工具,python实现,速度极快,篡改文件头尾信息以及还原
开发语言·windows·python