You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

优化基于ArrayList的泛型归并排序:避免Object数组与编译警告

泛型归并排序Merge阶段避免Object数组的方案

好问题!在泛型归并排序的merge阶段避开Object数组其实完全可行,核心是利用泛型的类型安全特性或者ArrayList本身的API来替代,不用再靠@SuppressWarnings("unchecked")压警告。下面给你几个实用的方案:

方案1:直接用ArrayList子列表拆分合并

这个方案最直观,完全不用数组,直接借助ArrayList的subList方法拆分左右两个子序列,然后直接比较合并回原列表。代码简洁易读,没有类型转换的麻烦:

public static <T> void merge(ArrayList<T> list, int left, int mid, int right, Comparator<T> comparator) {
    // 提取左右子列表(subList是视图,创建新ArrayList避免修改原列表时的联动影响)
    ArrayList<T> leftSub = new ArrayList<>(list.subList(left, mid + 1));
    ArrayList<T> rightSub = new ArrayList<>(list.subList(mid + 1, right + 1));
    
    int i = 0, j = 0, k = left;
    // 合并两个子列表到原列表
    while (i < leftSub.size() && j < rightSub.size()) {
        if (comparator.compare(leftSub.get(i), rightSub.get(j)) <= 0) {
            list.set(k++, leftSub.get(i++));
        } else {
            list.set(k++, rightSub.get(j++));
        }
    }
    
    // 处理左子列表剩余元素
    while (i < leftSub.size()) {
        list.set(k++, leftSub.get(i++));
    }
    // 处理右子列表剩余元素
    while (j < rightSub.size()) {
        list.set(k++, rightSub.get(j++));
    }
}

优点:代码简洁,无类型警告,无需反射,可读性拉满;
缺点:会创建两个临时ArrayList对象,有轻微的额外内存开销,但绝大多数业务场景下完全可以忽略。

方案2:通过反射创建类型安全的泛型数组

如果你不想创建额外的ArrayList对象,可以用Java反射的Array.newInstance方法直接创建T[]类型的数组,从根源上避免Object数组的转换:

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Comparator;

public static <T> void merge(ArrayList<T> list, int left, int mid, int right, Comparator<T> comparator) {
    int leftSize = mid - left + 1;
    int rightSize = right - mid;
    
    // 利用反射创建T类型的数组(注意:若list对应位置元素为null,getClass会抛NullPointerException)
    T[] leftArr = (T[]) Array.newInstance(list.get(left).getClass(), leftSize);
    T[] rightArr = (T[]) Array.newInstance(list.get(mid + 1).getClass(), rightSize);
    
    // 拷贝原列表元素到临时数组
    for (int i = 0; i < leftSize; i++) {
        leftArr[i] = list.get(left + i);
    }
    for (int j = 0; j < rightSize; j++) {
        rightArr[j] = list.get(mid + 1 + j);
    }
    
    // 标准合并逻辑
    int i = 0, j = 0, k = left;
    while (i < leftSize && j < rightSize) {
        if (comparator.compare(leftArr[i], rightArr[j]) <= 0) {
            list.set(k++, leftArr[i++]);
        } else {
            list.set(k++, rightArr[j++]);
        }
    }
    
    while (i < leftSize) {
        list.set(k++, leftArr[i++]);
    }
    while (j < rightSize) {
        list.set(k++, rightArr[j++]);
    }
}

如果担心null元素导致的异常,可以把Class<T>作为参数传入,让方法更安全:

public static <T> void merge(ArrayList<T> list, int left, int mid, int right, Comparator<T> comparator, Class<T> clazz) {
    int leftSize = mid - left + 1;
    int rightSize = right - mid;
    
    T[] leftArr = (T[]) Array.newInstance(clazz, leftSize);
    T[] rightArr = (T[]) Array.newInstance(clazz, rightSize);
    
    // 后续拷贝和合并逻辑同上
}

优点:无额外ArrayList对象,内存开销更小;
缺点:引入反射,代码复杂度略高,需要处理null元素的边界情况。

方案3:JDK17+用List.copyOf简化代码

如果你的项目用的是JDK17及以上,可以用List.copyOf创建不可变子列表,代码更简洁:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public static <T> void merge(ArrayList<T> list, int left, int mid, int right, Comparator<T> comparator) {
    List<T> leftSub = List.copyOf(list.subList(left, mid + 1));
    List<T> rightSub = List.copyOf(list.subList(mid + 1, right + 1));
    
    int i = 0, j = 0, k = left;
    while (i < leftSub.size() && j < rightSub.size()) {
        list.set(k++, comparator.compare(leftSub.get(i), rightSub.get(j)) <= 0 ? leftSub.get(i++) : rightSub.get(j++));
    }
    
    while (i < leftSub.size()) list.set(k++, leftSub.get(i++));
    while (j < rightSub.size()) list.set(k++, rightSub.get(j++));
}

优点:代码极度简洁,无类型警告,List.copyOf是JDK原生优化的方法,性能不错;
缺点:依赖JDK17+,兼容性有限。


内容的提问来源于stack exchange,提问作者JimBelushi2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:30:06