gpt4 book ai didi

java - 为什么不创建一个 Object[] 并转换为通用类型?解决办法是什么?

转载 作者:行者123 更新时间:2023-12-01 14:07:31 25 4
gpt4 key购买 nike

一些开发人员通过创建一个 Object[] 并转换为泛型类型来创建泛型数组,如本示例代码所示:

public class ArrTest<E> {

public void test(E a){
E[] b = (E[])new Object[1];
b[0] = a;
System.out.println(b[0]);
}

public static void main(String[] args){
ArrTest<String> t = new ArrTest<String>();
t.test("Hello World");
}
}

该示例将起作用,只是有一个警告:类型安全:未检查从 Object[] 到 E[] 的转换

是不是气馁了?这是创建泛型数组的最佳方式吗?如果我在我的软件中广泛使用此对象,这会导致意外结果或异常吗?

最佳答案

在问题的示例中 b变量不是 String[]即使我们将其转换为 E[]并定义了 EString在构建实例时。这是一个Object[] .发生这种情况是因为 Java 不知道什么类型 E是在运行时,因为在此示例中,我们没有为 E 定义父类.所以,它会自动有 Object作为其 parent 。

换句话说,public class ArrTest<E>public class ArrTest<E extends Object> 相同.

Java 不知道什么E在运行时,因为它是 unchecked . Unchecked意味着 Java 不会检查 E类型是定义的父类的扩展或实现。所以,Java 唯一知道的是 E在运行时是 <E extends Object> .

因此

E[] b = (E[]) new Object[1];

将执行为

Object[] b = (Object[]) new Object[1];

这就是为什么示例不会抛出 ClassCastException 的原因并且会使开发人员感到困惑。

如果我们尝试使用 b作为一个真正的String[]然后 Java 将抛出 ClassCastException因为 Java 将其视为 Object[] .例如,如果我们将方法更改为:

public E[] test(E a){
E[] b = (E[])new Object[1];
b[0] = a;
System.out.println(b[0]);
return b;
}

public static void main(String[] args){
ArrTest<String> t = new ArrTest<String>();
String[] result = t.test("Hello World");
}

现在我们将收到一个 ClassCastExceptionString[] result因为返回的类型将是 Object[]我们正在尝试将其存储在 String[] 中多变的。 Java 将看到类型差异并抛出异常。

这就是为什么类型转换 Object[]不鼓励使用通用数组,这只会导致困惑。

在写这个答案之前,我创建了一个测试用例,其中包含一些创建通用数组的可能方法,我得出结论认为这是最好的方法:

public class ExampleType<A extends Number>{
public <T extends A> T[] bestMethod(T[] array)
{
if(array.length < testSize)
array = (T[]) Array.newInstance(array.getClass().getComponentType(), testSize); //Type safety: Unchecked cast from Object to T[]
System.out.println("in this case: "+array.getClass().getComponentType().getSimpleName());
return array;
}
}

它保证返回与作为参数传递的数组类型相同的数组,并且它必须是 A 的实例。在 ExampleType<A extends Number> 中定义.如果你创建一个 ExampleTypeInteger你需要使用 Integer[]作为论据。如果你不想要 Integer 的数组具体来说,但你想存储任何类型的数字,你可以使用 Number[]作为参数。

如果您不需要类中的泛型类型,您可以将其简化为:

public <T> T[] bestMethod(T[] array)

如果你想让它返回 Number 的子类仅:

public <T extends Number> T[] bestMethod(T[] array)

如果你想自己测试的话,这是我的测试用例:

public class Test {
public static class ArrTest<E>
{
public void test(E a){
E[] b = (E[])new Object[1];
b[0] = a;
System.out.println(b[0]);
}
public E[] test2(E a){
E[] b = (E[])new Object[1];
b[0] = a;
System.out.println(b[0]+" "+b.getClass().getComponentType());
return b;
}
public static void main(String[] args){
ArrTest<String> t = new ArrTest<String>();
t.test("Hello World");
try{String[] result = t.test2("Hello World");}catch(Exception e){System.out.println(e);}
}
}

public static void main(String[] args) {
ArrTest.main(args);

System.out.println("#############\nWe want an array that stores only integers, sampledata: 1, samplearray: Integer");
test(new ExampleType<Integer>(Integer.class), 1, new Integer[0], new Integer[10]);

System.out.println("#############\nWe want an array that stores any type of Number, sampledata: 2L, samplearray: Number");
test(new ExampleType<Number>(Number.class), 2L, new Number[0], new Number[10]);

System.out.println("#############\nWe want an array that stores any type of CustomNumberA, sampledata: CustomB(3L), samplearray: CustomNumberA");
test(new ExampleType<CustomNumberA>(CustomNumberA.class), new CustomNumberB(3L), new CustomNumberA[0], new CustomNumberA[10]);

System.out.println("#############\nWe want A to be any type of number but we want to create an array of CustomNumberA, sampledata: CustomB(3L), samplearray: CustomNumberA");
test(new ExampleType<Number>(Number.class), new CustomNumberB(3L), new CustomNumberA[0], new CustomNumberA[10]);
}

public static <A extends Number> void test(ExampleType<A> testType, A sampleData, A[] smallSampleArray, A[] bigSampleArray)
{
Class<A> clazz = testType.clazz;
System.out.println("#############\nStarting tests with ExampleType<"+clazz.getSimpleName()+">");
System.out.println("============\nCreating with badMethod()...");
A[] array;
try
{
array = testType.badMethod();
testType.executeTests(array);
}
catch(Exception e){ System.out.println(">> ERR: "+e); }
System.out.println("============\nCreating with alsoBadMethod("+sampleData+" ["+sampleData.getClass().getSimpleName()+"])...");
try
{
array = testType.alsoBadMethod(sampleData);
testType.executeTests(array);
}
catch(Exception e){ System.out.println(">> ERR: "+e); }
System.out.println("============\nCreating with nearlyGoodMethod("+smallSampleArray.getClass().getSimpleName()+" len: "+smallSampleArray.length+")...");
try
{
array = testType.nearlyGoodMethod(smallSampleArray);
testType.executeTests(array);
}
catch(Exception e){ System.out.println(">> ERR: "+e); }
System.out.println("============\nCreating with nearlyGoodMethod("+bigSampleArray.getClass().getSimpleName()+" len: "+bigSampleArray.length+")...");
try
{
array = testType.nearlyGoodMethod(bigSampleArray);
testType.executeTests(array);
}
catch(Exception e){ System.out.println(">> ERR: "+e); }
System.out.println("============\nCreating with bestMethod("+smallSampleArray.getClass().getSimpleName()+" len: "+smallSampleArray.length+")...");
try
{
array = testType.bestMethod(smallSampleArray);
testType.executeTests(array);
}
catch(Exception e){ System.out.println(">> ERR: "+e); }
System.out.println("============\nCreating with bestMethod("+bigSampleArray.getClass().getSimpleName()+" len: "+bigSampleArray.length+")...");
try
{
array = testType.bestMethod(bigSampleArray);
testType.executeTests(array);
}
catch(Exception e){ System.out.println(">> ERR: "+e); }
}

@RequiredArgsConstructor @ToString()
public static class CustomNumberA extends Number{
@Delegate final Long n;
}

public static class CustomNumberB extends CustomNumberA{
public CustomNumberB(Long n) { super(n); }
}

@RequiredArgsConstructor
public static class ExampleType<A>{
private int testSize = 7;
final Class<A> clazz;

public A[] badMethod()
{
System.out.println("This will throw a ClassCastException when trying to return the array because Object is not a type of "+clazz.getSimpleName());
A[] array = (A[]) new Object[testSize]; //Warning: Type safety: Unchecked cast from Object[] to A[]
System.out.println("Array of "+array.getClass().getComponentType()+" created");
return array;
}

public A[] alsoBadMethod(A sampleType)
{
System.out.println("Will not respect A type ("+clazz.getSimpleName()+"), will always use the highest type in sampleType and tell that it's A[] but it's not, in this case will return "+sampleType.getClass().getSimpleName()+"[] and said it was "+clazz.getSimpleName()+"[] while developing");
A[] array = (A[]) Array.newInstance(sampleType.getClass(), testSize); //Type safety: Unchecked cast from Object to A[]
return array;
}

public A[] nearlyGoodMethod(A[] array)
{
System.out.println("The only guarantee is that the returned array will be of something that extends A ("+clazz.getSimpleName()+") so the returned type is not clear, may be of A or of the type passed in the argument but will tell it's A[] but may not be");
if(array.length < testSize)
array = (A[]) Array.newInstance(array.getClass().getComponentType(), testSize); //Type safety: Unchecked cast from Object to A[]
System.out.println("in this case: "+array.getClass().getComponentType().getSimpleName()+"[], expecting: "+clazz.getSimpleName()+"[]");
return array;
}

public <T extends A> T[] bestMethod(T[] array)
{
System.out.println("It's guaranteed to return on array of the same type as the sample array and it must be an instance of A, so, this is the best method");
if(array.length < testSize)
array = (T[]) Array.newInstance(array.getClass().getComponentType(), testSize); //Type safety: Unchecked cast from Object to T[]
System.out.println("in this case: "+array.getClass().getComponentType().getSimpleName()+"[], expecting: "+array.getClass().getComponentType().getSimpleName()+"[]");
return array;
}

public void executeTests(A[] array)
{
tryToSet(array, 0, 1);
tryToSet(array, 1, 2L);
tryToSet(array, 2, 3.1);
tryToSet(array, 3, 4F);
tryToSet(array, 4, (byte)0x5);
tryToSet(array, 5, new CustomNumberA(6L));
tryToSet(array, 6, new CustomNumberB(7L));
}

public void tryToSet(A[] array, int index, Object value)
{
System.out.println("Trying to set "+value+" ("+value.getClass().getSimpleName()+") at "+index+" in a array of "+array.getClass().getComponentType().getSimpleName());
try
{
if(array instanceof Object[]) ((Object[]) array)[index] = value;
else array[index] = (A) value; //Type safety: Unchecked cast from Object to A
System.out.println("## OK: Success: "+array.getClass().getComponentType().getSimpleName()+"["+index+"] = "+array[index]);
}
catch(Exception e){ System.out.println(">> ERR: "+e); }
}
}
}

这是测试结果...您可以看到 bestMethod总是返回预期的结果。

http://pastebin.com/CxBSHaYm

关于java - 为什么不创建一个 Object[] 并转换为通用类型?解决办法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21577493/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com