我创建数组的行给了Generic array creation
警告。
处理这个问题的好方法是什么?
public class Foo<T> {
void someMethod() {
Point[] points = new Point[3];
}
class Point {
float x, y;
}
}
答案 0 :(得分:8)
首先,让我们弄清楚Java认为new Point[3]
创建通用数组的原因,而Point
似乎是非泛型类。发生这种情况是因为Point
是非静态类,这意味着它具有对编译器嵌入的Foo<T>
的隐藏引用。该类看起来像Java:
class Foo$Point<T> {
Foo<T> _hidden_Foo;
float x, y;
}
程序文本中没有Foo$
,<T>
和_hidden_Foo
,但编译器认为它们是,因为Point
是一个内部类通用类Foo<T>
。
有两种方法可以解决这个问题:
static
为您的班级Point
,假设这是您打算做的。见ajb的答案。但是,Point
的任何实例方法都无法再访问Foo<T>
成员static
不是选项,请将数组替换为List<Point>
或其他适合您需要的集合。该限制仅适用于通用数组,但通用集合很好。以下是如何使用集合:
public class Foo<T> {
void someMethod() {
List<Point> points = new ArrayList<Point>();
... // add three points to the list
}
class Point {
float x, y;
}
}
答案 1 :(得分:3)
在我看来,您的Point
课程就在那里举行x
和y
,并且没有理由对其实例进行隐藏引用Foo<T>
。如果这是正确的,那么Point
应该是嵌套类,而不是内部类。添加static
关键字:
public class Foo<T> {
void someMethod() {
Point[] points = new Point[3];
}
static class Point {
float x, y;
}
}
答案 2 :(得分:2)
内部类也可以访问其外部类的泛型类型。让我们说我们有
class Foo<T> {
class Point {
float x, y;
T value;
T getValue(){
return value;
}
}
}
创建Foo
的实例时
Foo<String> f = new Foo<>();
我们可以基于其外部实例(如
)创建其内部类的实例Point p = f.new Point();
// or
//Foo<String>.Point p = f.new Point
// if we are creating it for instance outside of Foo class
并且编译器会知道p.getValue()
返回String,因此它可以让我们使用p.getValue().charAt(0)
。
现在问题是generic type can't be used in any part of array type,这意味着我们不能使用:
T[size]
。Foo<T>[size]
Foo<T>.Point[size]
最后一个例子似乎是你的情况,因为
Point[] points = new Point[3];
相当于
Point[] points = new Foo<T>.Point[3];
// Foo<T> is type of outer instance on which you are invoking new
您没有多少选择来解决此问题。
您可以明确表示您不希望通过编写
来使用泛型类型Point[] points = new Foo.Point[3];// we got rid of <T>
但请勿这样做,因为raw types are evil。
更好的解决方案是避免数组并使用支持List<Point>
等泛型的Collection。
List<Point> points = new ArrayList<>();
但最好的解决办法就是简单地摆脱T
对外层Foo
的依赖。这可以通过使您的内部类静态来实现,这意味着它不需要其外部类的实例,因此它不需要知道它使用哪种泛型类型。
所以你可以简单地使用
static class Point {
float x, y;
}
现在
Point[] points = new Point[3];
编译正常。
答案 3 :(得分:0)
Point
是一个非静态的内部类。所以Point
本身就是Foo<T>.Point
,这是一种参数化类型。您不能new Point[3]
(与new Foo<T>.Point[3]
相同),原因与您new ArrayList<T>[3]
相同。
所以,让我们进行类比并询问,当你想做什么时你会做什么
ArrayList<T>[] lists = new ArrayList<T>[3];
有两种方法:
创建原始类型的数组:
ArrayList<T>[] lists = new ArrayList[3];
或者,如果您不喜欢原始类型,请创建一个通配符参数化类型的数组:
ArrayList<T>[] lists = (ArrayList<T>[])new ArrayList<?>[3];
所以在我们的案例中,我们有两个相同的解决方案:
创建原始类型的数组。但是,原始类型是什么?它不是Point
,正如我们所发现的那样;因为那是隐式参数化的。相反,我们需要使用外部类名明确限定名称:Foo.Point
:
Point[] points = new Foo.Point[3];
或者,如果您不喜欢原始类型,请创建一个通配符参数化类型的数组:
Point[] lists = (Point[])new Foo<?>.Point[3];