内部 class 的通用数组创建
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;
}
}
在我看来,您的 Point
class 只是用来存放一个 x
和一个 y
,没有理由隐藏它引用 Foo<T>
的实例。如果这是正确的,那么 Point
应该是嵌套的 class,而不是内部的 class。添加 static
关键字:
public class Foo<T> {
void someMethod() {
Point[] points = new Point[3];
}
static class Point {
float x, y;
}
}
首先,让我们弄清楚为什么Java认为new Point[3]
创建了一个通用数组,而Point
似乎是一个非通用数组class。发生这种情况是因为 Point
是一个非静态 class,这意味着它有一个由编译器嵌入的对 Foo<T>
的隐藏引用。 class 对 Java 来说是这样的:
class Foo$Point<T> {
Foo<T> _hidden_Foo;
float x, y;
}
Foo$
、<T>
和 _hidden_Foo
不在程序的文本中,但编译器认为它们在,因为 Point
是一个内部class 的通用 class Foo<T>
.
有两种方法可以解决这个问题:
- 您可以将
static
设为您的 class 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;
}
}
内部 classes 也可以访问其外部 class 的通用类型。假设我们有
class Foo<T> {
class Point {
float x, y;
T value;
T getValue(){
return value;
}
}
}
当您创建 Foo
的实例时,例如
Foo<String> f = new Foo<>();
我们可以根据其外部实例创建其内部 class 的实例,例如
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()
returns 字符串,所以它可以让我们使用 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。
更好的解决方案是避免使用数组并使用支持泛型的 Collection,例如 List<Point>
.
List<Point> points = new ArrayList<>();
但最好的解决方案可能是简单地从外部 class Foo
中摆脱对 T
的依赖。这可以通过使内部 class 静态来实现,这意味着它不需要外部 class 的实例,因此它不需要知道它使用的是哪个泛型类型。
所以你可以简单地使用
static class Point {
float x, y;
}
现在
Point[] points = new Point[3];
编译正常。
Point
是一个非静态内部 class。所以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
;因为那是隐式参数化的。相反,我们需要使用外部 class 名称显式限定名称:Foo.Point
:
Point[] points = new Foo.Point[3];
或者,如果您不喜欢原始类型,请创建通配符参数化类型的数组:
Point[] lists = (Point[])new Foo<?>.Point[3];
我创建数组的行给了我一个 Generic array creation
警告。
有什么好的处理方法?
public class Foo<T> {
void someMethod() {
Point[] points = new Point[3];
}
class Point {
float x, y;
}
}
在我看来,您的 Point
class 只是用来存放一个 x
和一个 y
,没有理由隐藏它引用 Foo<T>
的实例。如果这是正确的,那么 Point
应该是嵌套的 class,而不是内部的 class。添加 static
关键字:
public class Foo<T> {
void someMethod() {
Point[] points = new Point[3];
}
static class Point {
float x, y;
}
}
首先,让我们弄清楚为什么Java认为new Point[3]
创建了一个通用数组,而Point
似乎是一个非通用数组class。发生这种情况是因为 Point
是一个非静态 class,这意味着它有一个由编译器嵌入的对 Foo<T>
的隐藏引用。 class 对 Java 来说是这样的:
class Foo$Point<T> {
Foo<T> _hidden_Foo;
float x, y;
}
Foo$
、<T>
和 _hidden_Foo
不在程序的文本中,但编译器认为它们在,因为 Point
是一个内部class 的通用 class Foo<T>
.
有两种方法可以解决这个问题:
- 您可以将
static
设为您的 classPoint
,假设这是您打算做的。请参阅 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;
}
}
内部 classes 也可以访问其外部 class 的通用类型。假设我们有
class Foo<T> {
class Point {
float x, y;
T value;
T getValue(){
return value;
}
}
}
当您创建 Foo
的实例时,例如
Foo<String> f = new Foo<>();
我们可以根据其外部实例创建其内部 class 的实例,例如
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()
returns 字符串,所以它可以让我们使用 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。
更好的解决方案是避免使用数组并使用支持泛型的 Collection,例如
List<Point>
.List<Point> points = new ArrayList<>();
但最好的解决方案可能是简单地从外部 class
Foo
中摆脱对T
的依赖。这可以通过使内部 class 静态来实现,这意味着它不需要外部 class 的实例,因此它不需要知道它使用的是哪个泛型类型。
所以你可以简单地使用static class Point { float x, y; }
现在
Point[] points = new Point[3];
编译正常。
Point
是一个非静态内部 class。所以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
;因为那是隐式参数化的。相反,我们需要使用外部 class 名称显式限定名称:Foo.Point
:Point[] points = new Foo.Point[3];
或者,如果您不喜欢原始类型,请创建通配符参数化类型的数组:
Point[] lists = (Point[])new Foo<?>.Point[3];