[英]Generic array creation of inner class
我创建数组的行给了我一个Generic array creation
警告。 处理这个问题的好方法是什么?
public class Foo<T> {
void someMethod() {
Point[] points = new Point[3];
}
class Point {
float x, y;
}
}
首先,让我们弄清楚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;
}
}
在我看来,你的Point
类只是持有一个x
和一个y
,并且它没有理由对一个Foo<T>
的实例有一个隐藏的引用。 如果这是正确的,那么Point
应该是嵌套类,而不是内部类。 添加static
关键字:
public class Foo<T> {
void someMethod() {
Point[] points = new Point[3];
}
static class Point {
float x, y;
}
}
内部类还可以访问其外部类的泛型类型。 让我们说我们有
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)
。
现在的问题是泛型类型不能在数组类型的任何部分使用 ,这意味着我们不能使用:
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>
但不要这样做,因为原始类型是邪恶的 。
更好的解决方案是避免使用数组并使用支持List<Point>
等泛型的Collection。
List<Point> points = new ArrayList<>();
但可能最好的解决方案是简单地摆脱外部类Foo
的T
的依赖性。 这可以通过使您的内部类静态来实现,这意味着它不需要其外部类的实例,因此它不需要知道它使用哪种泛型类型。
所以你可以简单地使用
static class Point { float x, y; }
现在
Point[] points = new Point[3];
将编译好。
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];
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.