This commit is contained in:
Looly
2025-12-15 17:08:49 +08:00
parent da85577867
commit 99a63b3c45
3 changed files with 567 additions and 0 deletions

View File

@@ -587,6 +587,9 @@ public class ArrayUtil extends PrimitiveArrayUtil {
* @since 3.2.2
*/
public static Class<?> getArrayType(final Class<?> componentType) {
if(null == componentType) {
return null;
}
return Array.newInstance(componentType, 0).getClass();
}

View File

@@ -0,0 +1,321 @@
/*
* Copyright (c) 2013-2025 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hutool.v7.core.array;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* {@link ArrayUtil} sub方法泛型版本单元测试
* 专门测试泛型版本的 sub 方法:
* - sub(A array, int beginInclude, int endExclude)
* - sub(A array, int beginInclude, int endExclude, int step)
*/
public class ArrayUtilSubGenericTest {
// region === 测试 sub(A array, int beginInclude, int endExclude) ===
@Test
public void testSubGeneric_withStringArray() {
// 测试正常截取
final String[] array = {"a", "b", "c", "d", "e"};
final String[] result = ArrayUtil.sub(array, 1, 4);
assertArrayEquals(new String[]{"b", "c", "d"}, result);
// 测试空数组
final String[] emptyArray = {};
final String[] emptyResult = ArrayUtil.sub(emptyArray, 0, 0);
assertArrayEquals(new String[]{}, emptyResult);
// 测试边界情况
final String[] fullCopy = ArrayUtil.sub(array, 0, 5);
assertArrayEquals(new String[]{"a", "b", "c", "d", "e"}, fullCopy);
// 测试超出范围
final String[] beyondEnd = ArrayUtil.sub(array, 3, 10);
assertArrayEquals(new String[]{"d", "e"}, beyondEnd);
// 测试负索引
final String[] negativeStart = ArrayUtil.sub(array, -4, 4);
assertArrayEquals(new String[]{"b", "c", "d"}, negativeStart);
final String[] negativeEnd = ArrayUtil.sub(array, 1, -1);
assertArrayEquals(new String[]{"b", "c", "d"}, negativeEnd);
}
@Test
public void testSubGeneric_withIntegerArray() {
// 测试整型数组
final Integer[] array = {1, 2, 3, 4, 5};
final Integer[] result = ArrayUtil.sub(array, 1, 4);
assertArrayEquals(new Integer[]{2, 3, 4}, result);
// 测试单个元素
final Integer[] singleResult = ArrayUtil.sub(array, 0, 1);
assertArrayEquals(new Integer[]{1}, singleResult);
// 测试反转索引
final Integer[] reversed = ArrayUtil.sub(array, 4, 1);
assertArrayEquals(new Integer[]{2, 3, 4}, reversed);
// 测试负索引
final Integer[] negativeResult = ArrayUtil.sub(array, -3, -1);
assertArrayEquals(new Integer[]{3, 4}, negativeResult);
}
@Test
public void testSubGeneric_withObjectArray() {
// 测试混合类型对象数组
final Object[] array = {"string", 123, 45.67, true, 'c'};
final Object[] result = ArrayUtil.sub(array, 1, 4);
assertArrayEquals(new Object[]{123, 45.67, true}, result);
// 测试单元素截取
final Object[] singleResult = ArrayUtil.sub(array, 2, 3);
assertArrayEquals(new Object[]{45.67}, singleResult);
}
@Test
public void testSubGeneric_withPrimitiveArrays() {
// 测试 int 数组
final int[] intArray = {1, 2, 3, 4, 5};
final int[] intResult = ArrayUtil.sub(intArray, 1, 4);
assertArrayEquals(new int[]{2, 3, 4}, intResult);
// 测试 double 数组
final double[] doubleArray = {1.1, 2.2, 3.3, 4.4};
final double[] doubleResult = ArrayUtil.sub(doubleArray, 0, 2);
assertArrayEquals(new double[]{1.1, 2.2}, doubleResult, 0.001);
// 测试 boolean 数组
final boolean[] boolArray = {true, false, true, false};
final boolean[] boolResult = ArrayUtil.sub(boolArray, 1, 3);
assertArrayEquals(new boolean[]{false, true}, boolResult);
// 测试 char 数组
final char[] charArray = {'a', 'b', 'c', 'd'};
final char[] charResult = ArrayUtil.sub(charArray, 2, 4);
assertArrayEquals(new char[]{'c', 'd'}, charResult);
}
@Test
public void testSubGeneric_edgeCases() {
// 测试空数组边界
final String[] emptyArray = {};
final String[] result1 = ArrayUtil.sub(emptyArray, 0, 0);
assertArrayEquals(new String[]{}, result1);
final String[] result2 = ArrayUtil.sub(emptyArray, 1, 3);
assertArrayEquals(new String[]{}, result2);
// 测试单元素数组
final String[] singleArray = {"only"};
final String[] singleResult = ArrayUtil.sub(singleArray, 0, 1);
assertArrayEquals(new String[]{"only"}, singleResult);
final String[] beyondSingle = ArrayUtil.sub(singleArray, 0, 5);
assertArrayEquals(new String[]{"only"}, beyondSingle);
final String[] emptyFromSingle = ArrayUtil.sub(singleArray, 1, 1);
assertArrayEquals(new String[]{}, emptyFromSingle);
// 测试索引翻转
final Integer[] array = {1, 2, 3, 4};
final Integer[] reversed = ArrayUtil.sub(array, 3, 0);
assertArrayEquals(new Integer[]{1, 2, 3}, reversed);
}
@Test
public void testSubGeneric_outOfBounds() {
// 测试索引超出范围的情况
final String[] array = {"a", "b", "c"};
// 起始位置超出数组长度
final String[] result1 = ArrayUtil.sub(array, 5, 10);
assertArrayEquals(new String[]{}, result1);
// 结束位置超过数组长度但起始位置有效
final String[] result2 = ArrayUtil.sub(array, 1, 10);
assertArrayEquals(new String[]{"b", "c"}, result2);
}
// endregion
// region === 测试 sub(A array, int beginInclude, int endExclude, int step) ===
@Test
public void testSubGenericWithStep_basicFunctionality() {
// 测试基本步进功能
final String[] array = {"a", "b", "c", "d", "e", "f", "g"};
// 步进为1正常截取
final String[] step1 = ArrayUtil.sub(array, 1, 6, 1);
assertArrayEquals(new String[]{"b", "c", "d", "e", "f"}, step1);
// 步进为2隔一个取一个
final String[] step2 = ArrayUtil.sub(array, 0, 7, 2);
assertArrayEquals(new String[]{"a", "c", "e", "g"}, step2);
// 步进为3隔两个取一个
final String[] step3 = ArrayUtil.sub(array, 0, 7, 3);
assertArrayEquals(new String[]{"a", "d", "g"}, step3);
}
@Test
public void testSubGenericWithStep_variousSteps() {
// 测试不同的步进值
final Integer[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 步进为2
final Integer[] step2 = ArrayUtil.sub(array, 0, 10, 2);
assertArrayEquals(new Integer[]{1, 3, 5, 7, 9}, step2);
// 步进为3
final Integer[] step3 = ArrayUtil.sub(array, 1, 10, 3);
assertArrayEquals(new Integer[]{2, 5, 8}, step3);
// 步进为4
final Integer[] step4 = ArrayUtil.sub(array, 2, 9, 4);
assertArrayEquals(new Integer[]{3, 7}, step4);
// 步进为5
final Integer[] step5 = ArrayUtil.sub(array, 0, 10, 5);
assertArrayEquals(new Integer[]{1, 6}, step5);
}
@Test
public void testSubGenericWithStep_edgeCases() {
// 测试边界情况
final String[] array = {"a", "b", "c", "d"};
// 步进大于数组长度
final String[] largeStep = ArrayUtil.sub(array, 0, 4, 10);
assertArrayEquals(new String[]{"a"}, largeStep);
// 空结果(起始位置等于结束位置)
final String[] empty = ArrayUtil.sub(array, 2, 2, 1);
assertArrayEquals(new String[]{}, empty);
// 单元素结果
final String[] single = ArrayUtil.sub(array, 1, 4, 3);
assertArrayEquals(new String[]{"b"}, single);
// 负索引
final Integer[] intArray = {1, 2, 3, 4, 5};
final Integer[] negativeIndex = ArrayUtil.sub(intArray, -3, -1, 1);
assertArrayEquals(new Integer[]{3, 4}, negativeIndex);
}
@Test
public void testSubGenericWithStep_primitiveArrays() {
// 测试基本类型数组
final int[] intArray = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
// 基本步进测试
final int[] step2 = ArrayUtil.sub(intArray, 0, 10, 2);
assertArrayEquals(new int[]{10, 30, 50, 70, 90}, step2);
final int[] step3 = ArrayUtil.sub(intArray, 1, 8, 3);
assertArrayEquals(new int[]{20, 50, 80}, step3);
// 测试 double 数组
final double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
final double[] doubleStep = ArrayUtil.sub(doubleArray, 1, 6, 2);
assertArrayEquals(new double[]{2.2, 4.4, 6.6}, doubleStep, 0.001);
}
@Test
public void testSubGenericWithStep_invalidStep() {
// 测试无效步进值 - 根据 ArrayWrapper.getSub 实现step <= 1 会被设为 1
final String[] array = {"a", "b", "c"};
// 步进为0 - 应该被设为1
final String[] step0 = ArrayUtil.sub(array, 0, 3, 0);
assertArrayEquals(new String[]{"a", "b", "c"}, step0);
// 负步进 - 应该被设为1
final String[] negativeStep = ArrayUtil.sub(array, 0, 3, -1);
assertArrayEquals(new String[]{"a", "b", "c"}, negativeStep);
// 步进为1 - 正常情况
final String[] step1 = ArrayUtil.sub(array, 0, 3, 1);
assertArrayEquals(new String[]{"a", "b", "c"}, step1);
}
@Test
public void testSubGenericWithStep_reversedIndexes() {
// 测试索引顺序颠倒的情况
final Integer[] array = {1, 2, 3, 4, 5};
// 正常顺序
final Integer[] normal = ArrayUtil.sub(array, 1, 4, 1);
assertArrayEquals(new Integer[]{2, 3, 4}, normal);
// 索引颠倒 - 应该自动纠正为升序
final Integer[] reversed = ArrayUtil.sub(array, 4, 1, 1);
assertArrayEquals(new Integer[]{2, 3, 4}, reversed);
// 步进为2的颠倒索引
final Integer[] reversedStep2 = ArrayUtil.sub(array, 4, 1, 2);
assertArrayEquals(new Integer[]{2, 4}, reversedStep2);
}
@Test
public void testSubGenericWithStep_emptyAndSmallArrays() {
// 测试空数组和小数组
final String[] emptyArray = {};
// 空数组的各种步进
final String[] emptyResult1 = ArrayUtil.sub(emptyArray, 0, 0, 1);
assertArrayEquals(new String[]{}, emptyResult1);
final String[] emptyResult2 = ArrayUtil.sub(emptyArray, 0, 5, 2);
assertArrayEquals(new String[]{}, emptyResult2);
// 单元素数组
final String[] singleArray = {"only"};
final String[] singleResult1 = ArrayUtil.sub(singleArray, 0, 1, 1);
assertArrayEquals(new String[]{"only"}, singleResult1);
final String[] singleResult2 = ArrayUtil.sub(singleArray, 0, 1, 2);
assertArrayEquals(new String[]{"only"}, singleResult2);
// 双元素数组
final String[] doubleArray = {"first", "second"};
final String[] doubleResult1 = ArrayUtil.sub(doubleArray, 0, 2, 1);
assertArrayEquals(new String[]{"first", "second"}, doubleResult1);
final String[] doubleResult2 = ArrayUtil.sub(doubleArray, 0, 2, 2);
assertArrayEquals(new String[]{"first"}, doubleResult2);
}
@Test
public void testSubGeneric_nullInput() {
// 测试空指针输入
assertThrows(IllegalArgumentException.class, () -> {
ArrayUtil.sub((String[]) null, 0, 1);
});
assertThrows(IllegalArgumentException.class, () -> {
ArrayUtil.sub((String[]) null, 0, 1, 1);
});
}
// endregion
}

View File

@@ -1194,4 +1194,247 @@ public class ArrayUtilTest {
assertNotEquals(Arrays.toString(initialArray), Arrays.toString(shuffledArray));
}
@Test
public void swapTest() {
// 正常交换场景
final String[] array = {"a", "b", "c", "d"};
final String[] swapped = ArrayUtil.swap(array, 1, 2);
// 验证交换后的数组内容
assertArrayEquals(new String[]{"a", "c", "b", "d"}, swapped);
// 验证返回的是同一个数组对象
assertSame(array, swapped);
// 验证原数组也被修改
assertArrayEquals(new String[]{"a", "c", "b", "d"}, array);
}
@Test
public void swapTestBoundaryIndices() {
// 边界索引交换:第一个和最后一个元素
final Integer[] array = {1, 2, 3, 4, 5};
final Integer[] swapped = ArrayUtil.swap(array, 0, 4);
assertArrayEquals(new Integer[]{5, 2, 3, 4, 1}, swapped);
assertSame(array, swapped);
}
@Test
public void swapTestSameIndex() {
// 相同索引交换,数组应保持不变
final String[] array = {"x", "y", "z"};
final String[] swapped = ArrayUtil.swap(array, 1, 1);
assertArrayEquals(new String[]{"x", "y", "z"}, swapped);
assertSame(array, swapped);
}
@Test
public void swapTestEmptyArray() {
// 空数组应该抛出异常
final String[] emptyArray = {};
final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> ArrayUtil.swap(emptyArray, 0, 1));
assertEquals("Array must not empty !", exception.getMessage());
}
@Test
public void swapTestNullArray() {
// null数组应该抛出异常
final String[] nullArray = null;
final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> ArrayUtil.swap(nullArray, 0, 1));
assertEquals("Array must not empty !", exception.getMessage());
}
@Test
public void swapTestNegativeIndex() {
// 负索引应该抛出异常
final Integer[] array = {1, 2, 3};
final ArrayIndexOutOfBoundsException exception = assertThrows(ArrayIndexOutOfBoundsException.class,
() -> ArrayUtil.swap(array, -1, 1));
assertTrue(exception.getMessage().contains("-1"));
}
@Test
public void swapTestIndexOutOfBounds() {
// 越界索引应该抛出异常
final String[] array = {"a", "b", "c"};
final ArrayIndexOutOfBoundsException exception = assertThrows(ArrayIndexOutOfBoundsException.class,
() -> ArrayUtil.swap(array, 0, 5));
assertTrue(exception.getMessage().contains("5"));
}
@Test
public void swapTestMultipleTypes() {
// 测试不同类型数组的交换
final Integer[] intArray = {1, 2, 3};
final Integer[] swappedInt = ArrayUtil.swap(intArray, 0, 2);
assertArrayEquals(new Integer[]{3, 2, 1}, swappedInt);
final Double[] doubleArray = {1.1, 2.2, 3.3};
final Double[] swappedDouble = ArrayUtil.swap(doubleArray, 1, 2);
assertArrayEquals(new Double[]{1.1, 3.3, 2.2}, swappedDouble);
final Boolean[] boolArray = {true, false, true};
final Boolean[] swappedBool = ArrayUtil.swap(boolArray, 0, 1);
assertArrayEquals(new Boolean[]{false, true, true}, swappedBool);
}
// region ----- getComponentType tests
@Test
public void getComponentTypeObjectTestWithObjectArray() {
// 测试 Object 数组
final Object[] objectArray = new Object[]{"test", 123};
final Class<?> result = ArrayUtil.getComponentType(objectArray);
assertEquals(Object.class, result, "Object[] 应返回 Object.class");
}
@Test
public void getComponentTypeObjectTestWithStringArray() {
// 测试 String 数组
final String[] stringArray = new String[]{"a", "b", "c"};
final Class<?> result = ArrayUtil.getComponentType(stringArray);
assertEquals(String.class, result, "String[] 应返回 String.class");
}
@Test
public void getComponentTypeObjectTestWithPrimitiveIntArray() {
// 测试基本类型 int 数组
final int[] intArray = new int[]{1, 2, 3};
final Class<?> result = ArrayUtil.getComponentType(intArray);
assertEquals(int.class, result, "int[] 应返回 int.class");
}
@Test
public void getComponentTypeObjectTestWithIntegerArray() {
// 测试包装类型 Integer 数组
final Integer[] integerArray = new Integer[]{1, 2, 3};
final Class<?> result = ArrayUtil.getComponentType(integerArray);
assertEquals(Integer.class, result, "Integer[] 应返回 Integer.class");
}
@Test
public void getComponentTypeObjectTestWithNonArrayObject() {
// 测试非数组对象
final String nonArray = "not an array";
final Class<?> result = ArrayUtil.getComponentType(nonArray);
assertNull(result, "非数组对象应返回 null");
}
@Test
public void getComponentTypeObjectTestWithEmptyArray() {
// 测试空数组
final String[] emptyArray = new String[0];
final Class<?> result = ArrayUtil.getComponentType(emptyArray);
assertEquals(String.class, result, "空 String 数组应返回 String.class");
}
@Test
public void getComponentTypeObjectTestWithMultiDimensionalArray() {
// 测试多维数组
final int[][] multiDimArray = new int[2][3];
final Class<?> result = ArrayUtil.getComponentType(multiDimArray);
assertEquals(int[].class, result, "int[][] 应返回 int[].class");
}
@Test
public void getComponentTypeClassTestWithObjectArrayClass() {
// 测试 Object 数组 Class
final Class<?> result = ArrayUtil.getComponentType(Object[].class);
assertEquals(Object.class, result, "Object[].class 应返回 Object.class");
}
@Test
public void getComponentTypeClassTestWithStringArrayClass() {
// 测试 String 数组 Class
final Class<?> result = ArrayUtil.getComponentType(String[].class);
assertEquals(String.class, result, "String[].class 应返回 String.class");
}
@Test
public void getComponentTypeClassTestWithPrimitiveIntArrayClass() {
// 测试基本类型 int 数组 Class
final Class<?> result = ArrayUtil.getComponentType(int[].class);
assertEquals(int.class, result, "int[].class 应返回 int.class");
}
@Test
public void getComponentTypeClassTestWithIntegerArrayClass() {
// 测试包装类型 Integer 数组 Class
final Class<?> result = ArrayUtil.getComponentType(Integer[].class);
assertEquals(Integer.class, result, "Integer[].class 应返回 Integer.class");
}
@Test
public void getComponentTypeClassTestWithNonArrayClass() {
// 测试非数组 Class
final Class<?> result = ArrayUtil.getComponentType(String.class);
assertNull(result, "String.class 应返回 null");
}
@Test
public void getComponentTypeClassTestWithMultiDimensionalArrayClass() {
// 测试多维数组 Class
final Class<?> result = ArrayUtil.getComponentType(int[][].class);
assertEquals(int[].class, result, "int[][].class 应返回 int[].class");
}
@Test
public void getComponentTypeClassTestWithPrimitiveArrayType() {
// 测试所有基本类型数组
assertEquals(boolean.class, ArrayUtil.getComponentType(boolean[].class));
assertEquals(byte.class, ArrayUtil.getComponentType(byte[].class));
assertEquals(char.class, ArrayUtil.getComponentType(char[].class));
assertEquals(short.class, ArrayUtil.getComponentType(short[].class));
assertEquals(int.class, ArrayUtil.getComponentType(int[].class));
assertEquals(long.class, ArrayUtil.getComponentType(long[].class));
assertEquals(float.class, ArrayUtil.getComponentType(float[].class));
assertEquals(double.class, ArrayUtil.getComponentType(double[].class));
}
@Test
public void getComponentTypeClassTestWithCustomObjectArray() {
// 测试自定义对象数组
final Class<?> result = ArrayUtil.getComponentType(ArrayUtil[].class);
assertEquals(ArrayUtil.class, result, "ArrayUtil[].class 应返回 ArrayUtil.class");
}
// endregion
// region ----- getArrayType tests
@Test
void testGetArrayTypeForPrimitive() {
assertEquals(int[].class, ArrayUtil.getArrayType(int.class));
assertEquals(double[].class, ArrayUtil.getArrayType(double.class));
assertEquals(boolean[].class, ArrayUtil.getArrayType(boolean.class));
}
@Test
void testGetArrayTypeForObject() {
assertEquals(String[].class, ArrayUtil.getArrayType(String.class));
assertEquals(Integer[].class, ArrayUtil.getArrayType(Integer.class));
}
@Test
void testGetArrayTypeForInterface() {
assertEquals(Runnable[].class, ArrayUtil.getArrayType(Runnable.class));
assertEquals(Comparable[].class, ArrayUtil.getArrayType(Comparable.class));
}
@Test
void testGetArrayTypeForAbstractClass() {
assertEquals(Number[].class, ArrayUtil.getArrayType(Number.class));
}
@Test
void testGetArrayTypeForNull() {
assertNull(ArrayUtil.getArrayType(null));
}
// endregion
}