繁体   English   中英

内部类的通用数组创建

[英]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

您没有多少选择来解决此问题。

  1. 您可以明确表示您不希望通过编写使用泛型类型

     Point[] points = new Foo.Point[3];// we got rid of <T> 

    但不要这样做,因为原始类型是邪恶的

  2. 更好的解决方案是避免使用数组并使用支持List<Point>等泛型的Collection。

     List<Point> points = new ArrayList<>(); 
  3. 但可能最好的解决方案是简单地摆脱外部类FooT的依赖性。 这可以通过使您的内部类静态来实现,这意味着它不需要其外部类的实例,因此它不需要知道它使用哪种泛型类型。
    所以你可以简单地使用

     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];

有两种方法:

  1. 创建原始类型的数组:

    ArrayList<T>[] lists = new ArrayList[3];

  2. 或者,如果您不喜欢原始类型,请创建通配符参数化类型的数组:

    ArrayList<T>[] lists = (ArrayList<T>[])new ArrayList<?>[3];

所以在我们的例子中,我们有两个相同的解决方案:

  1. 创建原始类型的数组。 但是,什么是原始类型? 正如我们所发现的那样,它不是Point ; 因为这是隐式参数化的。 相反,我们需要使用外部类名明确限定名称: Foo.Point

    Point[] points = new Foo.Point[3];

  2. 或者,如果您不喜欢原始类型,请创建通配符参数化类型的数组:

    Point[] lists = (Point[])new Foo<?>.Point[3];

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM