【问题标题】:Generic array creation of inner class内部类的通用数组创建
【发布时间】:2015-03-14 04:31:11
【问题描述】:

我创建数组的行给了我一个Generic array creation 警告。 有什么好的方法来解决这个问题?

public class Foo<T> {

    void someMethod() {
        Point[] points = new Point[3];
    }

    class Point {
        float x, y;
    }
}

【问题讨论】:

  • static class Point {...。看起来你的内部类只是用来保存xy,并不需要一个指向Foo&lt;T&gt; 实例的隐藏指针。如果我是对的,那么它应该是嵌套类而不是内部类。
  • @ajb 这应该是一个答案(因为它是答案)。
  • 有趣的是为什么Point p = new Point() 编译得很好,而Point[] points = new Points[3] 没有。
  • @Pshemo 即使List&lt;Point&gt; points = new ArrayList&lt;Point&gt;() 编译良好,该限制仅适用于数组。

标签: java generics inner-classes


【解决方案1】:

在我看来,您的Point 类只是用来保存xy,并且没有理由隐藏对Foo&lt;T&gt; 实例的引用。如果这是正确的,那么Point 应该是一个嵌套类,而不是一个内部类。添加static关键字:

public class Foo<T> {

    void someMethod() {
        Point[] points = new Point[3];
    }

    static class Point {
        float x, y;
    }
}

【讨论】:

    【解决方案2】:

    首先,让我们弄清楚为什么Java 认为new Point[3] 创建了一个泛型数组,而Point 似乎是一个非泛型类。发生这种情况是因为Point 是一个非静态类,这意味着它具有编译器嵌入的对Foo&lt;T&gt; 的隐藏引用。这个类在 Java 中看起来像这样:

    class Foo$Point<T> {
        Foo<T> _hidden_Foo;
        float x, y;
    }
    

    Foo$&lt;T&gt;_hidden_Foo 不在程序文本中,但编译器认为它们存在,因为 Point 是泛型类 Foo&lt;T&gt; 的内部类。

    有两种方法可以解决这个问题:

    • 您可以将static 设为您的班级Point,假设您打算这样做。请参阅 ajb 的答案。但是,Point 的任何实例方法将不再能够访问Foo&lt;T&gt; 的成员
    • 如果static 不是一个选项,请将数组替换为List&lt;Point&gt; 或其他适合您需要的集合。该限制仅适用于泛型数组,但泛型集合很好。

    以下是使用集合的方法:

    public class Foo<T> {
        void someMethod() {
            List<Point> points = new ArrayList<Point>();
            ... // add three points to the list
        }
        class Point {
            float x, y;
        }
    }
    

    【讨论】:

    • 我不确定Foo$Point&lt;T&gt;。如果我没记错的话,它会在Point 中声明T,这与Foo&lt;T&gt; 不同。你有任何消息来源可以证实吗?
    • @Pshemo 我认为Foo$Point&lt;T&gt; 中的T 将独立于Foo&lt;T&gt; 中的T。我放了&lt;T&gt; 来说明为什么Point 变得通用,假装它是一个顶级类。我并不打算暗示 Java 编译器会生成与此完全相同的代码,只是 (1) 会有对外部上下文的 Foo&lt;T&gt; 的引用,以及 (2) 这就是为什么 Point 类会被认为是通用的.
    【解决方案3】:

    内部类也可以访问其外部类的泛型类型。假设我们有

    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&lt;T&gt;[size]
    • 甚至没有Foo&lt;T&gt;.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>
      

      但不要这样做,因为raw types are evil

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

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

      static class Point {
          float x, y;
      }
      

      现在

      Point[] points = new Point[3]; 
      

      可以正常编译。

    【讨论】:

      【解决方案4】:

      Point 是一个非静态内部类。所以Point自己写的意思是Foo&lt;T&gt;.Point,一个参数化的类型。你不能做new Point[3](和new Foo&lt;T&gt;.Point[3]一样),同样的原因你不能做new ArrayList&lt;T&gt;[3]

      所以让我们打个比方,问一下,当你想做的时候,你会做什么

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

      有两种方式:

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

        ArrayList&lt;T&gt;[] lists = new ArrayList[3];

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

        ArrayList&lt;T&gt;[] lists = (ArrayList&lt;T&gt;[])new ArrayList&lt;?&gt;[3];

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

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

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

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

        Point[] lists = (Point[])new Foo&lt;?&gt;.Point[3];

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-15
        • 2012-11-15
        • 1970-01-01
        相关资源
        最近更新 更多