这是我正在使用的代码
public class aClass<T> {
private T[] elements;
public aClass(T[] elements) {
this.elements = elements;
}
public void doSomething() {
T[] newArray = (T[]) new Object[5];
...
}
}
我见过有人说创建像这样的数组是一个坏主意,因为它不是类型安全的。但是,每次我使用它,我都没有问题。何时创建这样的数组会导致问题?
由于
答案 0 :(得分:4)
你不能创建一个T数组,因为Java在运行时不知道什么是T的类型。这是因为Java泛型是用类型擦除实现的。这意味着在确保一切正常后,编译器会丢弃大多数泛型类型信息。
对于数组,故事是不同的,因为Java需要知道T的确切类型才能创建给定的数组,并且由于无法确定这样的事情,所以无法创建泛型类型的数组。
您可以做的是提供要使用的实际数组的实例,Java编译器可以确保它具有适当的类型:
public static <T> void fillWith(T[] destiny, List<? extends T> source){
for(int i=0; i<= destiny.length; i++){
destiny[i] = source.get(i);
}
}
java.utils.Arrays.copy
方法提供了一种使用泛型和反射的替代方法,您可以将其用作您想要做的参考。
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
答案 1 :(得分:4)
以下是导致问题的示例:
public class Main {
public static class List<E extends Number> {
private E[] myE;
public void hello(E e) {
E[] newArray = (E[]) new Object[5];
for (int i = 0; i < newArray.length; i++) {
newArray[i] = e;
}
myE = newArray;
}
}
public static <T> T[] createArray(int size) {
return (T[]) new Object[size];
}
public static void main(String[] args) throws IOException {
List<Integer> integers = new List<Integer>();
integers.hello(5);
}
}
您的代码有效,因为当您声明通用参数<T>
时,它是未绑定的,这意味着它扩展了Object
。当您将数组转换为(T[])
时,实际上是在转换为(Object[])
,因为这是编译器可以做的最好的。现在,如果将数组保留在代码中,则不应该有太多问题。但是,如果代码外部的某个人可以检索该数组并使用除object之外的类型实例化您的类,则他将具有ClassCastException。
答案 2 :(得分:2)
不安全的东西本身并不会产生问题。但它可以在编译时隐藏问题,直到合适的时刻才能弹出。
您可以在没有问题的情况下在非安全的环境中完全工作,但这只是一个坏习惯,因为类型安全的环境确保您不会拥有一组公共运行时错误,你现在没有,但你没有任何保证,这些非常重要,任何你可以信赖的安全意味着更少的努力。
答案 3 :(得分:1)
其他人错了。除非在创建时有类型的实例,否则没有其他方法可以创建数组。另请参阅How to create a generic array in Java?
如果您有类型实例(=具有类型Class<T>
的东西),您可以调用java.lang.reflect.Array.newInstance(Class<?>, int)
,但即便如此,您还需要演员,所以为什么要这么麻烦?
如果elements
的类型是Object
而不是T
,我会说情况有所不同,但事实并非如此,代码完全没问题。
如果你想进一步隐藏它,你可以写一个辅助方法:
@SuppressWarnings( "unchecked" )
public static <T> T[] createArray( int size ) {
return (T[]) new Object[size];
}
当你调用它时,它会创建一个不需要强制转换的数组。
答案 4 :(得分:1)
在这种情况下使用Collection
会更安全。只需制作类似
...
Collection<T> newElements = new ArrayList<T>(5);
...
无论如何,从我所知道的创建像这样的通用数组不会给你带来真正的问题,但是“闻起来很糟糕”,因为它需要显式的类型转换。在这种情况下你真的需要一个阵列吗?
答案 5 :(得分:1)
我见过有人说创建这样的数组是件坏事 这个想法,因为它不是类型安全的。但是,每次我使用它,我 没问题。何时会像这样创建一个数组 一个问题?
人们说这是一个坏主意,因为从逻辑上讲,如果Object[]
不是T[]
,则将运行时类型为T
的对象转换为Object
类型是不正确的}。
但是,您没有看到任何直接问题,因为在课堂内(T
范围内),T
被删除。因此,不会检查从Object[]
到T[]
的演员表。
如果您所做的只是在您的类中使用此变量(在类型变量T
的范围内),并且您永远不会将它返回给类外的人,并且除了class可以访问它,然后它不会导致任何问题。
事实上,你正在做的方式有好处 - 在获取和设置数组的元素时,你可以获得泛型类型检查的所有好处,如果你只是按照完全“类型”就不会得到-safe“使用类型为Object[]
的变量的解决方案,在这种情况下,您必须手动转换从中获取的内容。
如果您将此数组变量返回到外部(或以其他方式允许外部访问它)作为类型T[]
,您将遇到问题,因为调用代码将期望某种类型的数组,并且泛型将在接收到此数组时在调用代码中插入强制转换,并且强制转换将在运行时失败(因为例如Object[]
不是String[]
;它们在运行时是不同的类型。这是一个简单的例子:
public class aClass<T> {
private T[] elements;
public aClass(T[] elements) {
this.elements = elements;
}
public void doSomething() {
elements = (T[]) new Object[5];
...
}
public T[] getArray() {
return elements;
}
}
// some other code...
aClass<String> foo = new aClass<String>(new String[2]);
foo.doSomething();
String[] bar = foo.getArray(); // ClassCastException here
答案 6 :(得分:0)
您可能在比较和打印时遇到问题..基本上任何知道类型对格式化很重要的时候。你有它的方式系统不知道数组中的数据