所以我知道你不能“轻松地”在Java中创建泛型类型的数组(但是你可以创建集合)。我最近遇到了一个需要二维对象数组(即Generic)的情况。这是一个“粗略”的概念,它看起来像什么(不完整,但我想尽可能简短):
class Outer<T> {
private Foo[][] foo;
abstract class Foo extends Blah<T> {
public List<T> getContents ();
}
abstract class Bar extends Foo {
...
}
}
所以代码中的某处我需要一个数组:
foo = new Foo[width][height];
(我们知道不可能发生)。但是,我试过这个:
foo = (Foo[][])Array.newInstance (Foo.class, new int[]{getWidth (), getHeight ()});
虽然我不得不压制警告但编译器接受了。我想我的问题是“这会把我扼杀在某个地方吗?成员”foo“永远不会暴露在外面(虽然类型Foo和Bar都是)。我知道它很难看,但它绝对有效,这使得我不必创建其他“psedu-kludge”,这可能会导致课程覆盖“外部”课程更令人头疼。提前致谢!
这更接近我实际做的事情;当然,我认为Map类中有许多支持方法和其他逻辑,为了简洁起见,我已经遗漏了这些方法和其他逻辑。
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
interface Cell<T> {
public void add (T t);
public boolean remove (T t);
public List<T> getAll ();
public Map<T> getMap ();
}
class Map<T> {
protected BaseCell map[][];
public abstract class BaseCell implements Cell<T> {
private List<T> contents;
public BaseCell () {
this.contents = new ArrayList<T> ();
}
public void add (T t) {
this.contents.add (t);
}
public boolean remove (T t) {
return this.contents.remove (t);
}
public List<T> getAll () {
return this.contents;
}
public Map<T> getMap () {
return Map.this;
}
abstract public boolean test ();
}
public class SpecialCell extends BaseCell {
@Override
public boolean test() {
return true;
}
}
public class SpecialCell2 extends BaseCell {
@Override
public boolean test() {
return false;
}
}
@SuppressWarnings("unchecked")
public Map (int width, int height) {
this.map = (BaseCell[][])Array.newInstance(BaseCell.class, new int[] {width, height});
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (Math.random() < .5) {
this.map[x][y] = new SpecialCell ();
} else {
this.map[x][y] = new SpecialCell2 ();
}
}
}
}
public BaseCell getCellAt (int x, int y) {
return this.map[x][y];
}
}
public class Junk {
/**
* @param args
*/
public static void main(String[] args) {
class Occupant {
}
Map<Occupant> map = new Map<Occupant> (50, 50);
map.getCellAt(10, 10).add(new Occupant ());
map.getCellAt(10, 10).getMap ();
for (int y = 0; y < 50; y++) {
for (int x = 0; x < 50; x++) {
System.out.print (map.getCellAt (x, y).test () ? "1" : "0");
}
System.out.println ();
}
}
}
答案 0 :(得分:2)
您正在做的事情是安全的,因为您正在控制未曝光的map
。您可能应该将其设为私有而不受保护,否则扩展类可能会错误地操纵它。您可以通过强制转换为运行时检查来消除编译器警告,如下所示:
this.map = BaseCell[][].class.cast(Array.newInstance(BaseCell.class,
new int[] { width, height }));
然后,如果稍后某些代码可能以不兼容的方式更改,编译器警告将屏蔽掉,那么至少会在构造map
时因运行时异常而中断。请记住,Generics只是在编译时被删除。
答案 1 :(得分:1)
我认为在这种情况下最好的选择就是使用Object[]
。
在泛型之前,数组类型X[]
其中X!=Object
是API中的重要类型。我们无法使用无法指定组件类型的List
。 X[]
是最有用的。现在 泛型,我们最好在API中使用List<X>
而不是X[]
。 (JDK仍在其API中使用X[]
,甚至更新的API,可能是因为他们希望避免其包之间存在依赖关系)
那是API。 在实施细节中,我们仍然需要数组,它们是不可或缺的。但是,Object[]
就足够了。实际上,如果Java只保留Object[]
并删除所有其他引用数组类型,那么不会发生任何严重错误。我们所需要的只是编写程序的对象数组。
当然,当X[]
可用且易于使用时,限制自己使用它是愚蠢的。
如果X
不是一个简单的类,并且X[]
难以使用,浪费我们的时间来使它工作,那同样很愚蠢。没有什么好处真正实现。在这种情况下,只需使用Object[]
,我们就可以省去很多麻烦。
结论:外部,不接受数组,不给出数组;在内部,如果没有汗水,请使用X[]
,然后使用Object[]
并感到高兴。
答案 2 :(得分:1)
答案 3 :(得分:0)
此Foo[][]
的问题在于它实际上被定义为Outer<T>.Foo[][]
,但VM无法控制(使用ArrayStoreException
s)您未放置Outer<S>.Foo
{1}}中的对象 - 这就是你收到警告的原因。 (这就是通用数组通常不被认为是类型安全的原因。)
如果您确定不是这种情况,那么您没有问题。
答案 4 :(得分:0)
这将允许它工作(以及未经检查的强制转换,这对于这种情况是正常的,因为您希望拥有一个泛型类型的变量)。解决方案是意识到只有Foo
引用参数化类Outer<T>.Foo
,因为您在Outer<T>
的范围内;要获得实际的原始类,您需要明确地将其限定为Outer.Foo
:
foo = (Foo[][])new Outer.Foo[width][height];