【问题标题】:Why static nested class?为什么是静态嵌套类?
【发布时间】:2015-02-12 01:56:45
【问题描述】:

我有一个尝试的示例代码。该代码似乎没有编译错误。为什么它使用静态嵌套类节点?当我删除Node 嵌套类中的static 并编译时,错误显示private Node[] next = new Node[R]; 中的create generic array。到底发生了什么?

public class TrieST<Value> {
    private static final int R = 256;        // extended ASCII


    private Node root;      // root of trie
    private int N;          // number of keys in trie

    // R-way trie node
    private static class Node {
        private Object val;
        private Node[] next = new Node[R];
    }


    public TrieST() {
    }
}

【问题讨论】:

  • 首先,您知道为什么不允许使用泛型数组吗? (例如new ArrayList&lt;String&gt;[5]; 显示此错误)
  • How to create a generic array? 的可能重复项
  • 你能解释一下为什么添加static时没有这个错误吗?
  • 因为您使用静态创建:Node[] next = new Node[R] 并且使用非静态内部类创建一个与外部类实例关联的节点,该实例具有通用类型。并且禁止创建泛型数组。
  • 请注意,“静态内部”在术语上是矛盾的。嵌套类是要么静态内部。

标签: java


【解决方案1】:

假设在您的代码 sn-p 中您使用的是非静态内部类而不是像这样的静态嵌套类:private class Node,在这种情况下,您将尝试实例化一个 Array,它不是可能,我们不能在泛型类中实例化Array,因为泛型在运行时没有关于其类型的任何信息,而数组创建表达式指定元素类型。

因此,使用 Static Nested Class 编译的原因是此类类被视为“顶级”类(就行为而言):

静态嵌套类与其外部的实例成员交互 类(和其他类)就像任何其他顶级类一样。在 实际上,静态嵌套类在行为上是一个顶级类 为了打包方便,已经嵌套在另一个顶级类中。

现在,让我们考虑所有这些,回到编译器显示的确切错误:

无法创建TrieST&lt;Value&gt;.Node 的通用数组

这意味着您要创建的array 的类型是TrieST&lt;Value&gt;.Node,其运行时的类型未知,因此可能会在next 数组中插入不同的类型。更清晰和解释清楚的例子可以在Cannot Create Arrays of Parameterized Types找到。

然而,静态嵌套类不表现作为TrieST&lt;Value&gt; 的内部类,因此在Node 中创建一个数组不会是非法的,因为它不是TrieST&lt;Value&gt;.Node 类型,它属于Node 类型(like,如果它是顶级类)。

【讨论】:

  • 您能否解释一下嵌套静态 lass 为何以及如何将这个错误视为顶级类?
  • 顶级类是非内部类,这意味着静态嵌套类与外部类之间没有隐式关系,因此实例化数组不会影响外部类(你的通用类)
  • @Peterxwl 我刚刚添加了更新,请立即查看
  • @alfas in the java docs“静态嵌套类在行为上是一个顶级类”这就是为什么我说“被认为”,很明显它不是一个!这就是我引用javadocs的原因!但我使用“考虑”或“所谓”的术语来澄清问题
  • @alfasin “它是一个内部静态类。” 静态嵌套类不是内部的。 "An inner class is a nested class that is not declared static." 嵌套类可以是内部的或静态的。
【解决方案2】:

因为您使用静态创建:Node[] next = new Node[R] 并且使用非静态内部类创建一个与外部类实例相关联的节点,该实例具有泛型类型。并且禁止创建泛型数组。

但是,让我们备份几个步骤:实例化内部类(非静态)的方式如下(示例):

class TrieST<V> {
    private static final int R = 256;        

    private Node root;      // root of trie
    private int N;          // number of keys in trie
    private TrieST<String> inst = new TrieST<String>(); // must create an instance of the outer class first

    // R-way trie node
    private class Node {
        private Object val;
        private TrieST<String>.Node next =  inst.new Node(); //must use an instance of the outer class to instantiate an object of the inner class
    }

    public TrieST() {
    }
}

现在,如果我们尝试将上面的实现从内部类的实例更改为数组,我们将得到generic array creation,因为由于协方差 数组的性质(Shape[]superTriangle[])不能很好地与泛型的不变性质(List&lt;Object&gt;不是 List&lt;String&gt; 的超级用户。如果您想深入了解,Bloch 在“Effective Java”中提供了更详细的解释。

如果你坚持使用内部类,你可以通过使用Array.newInstance() 来绕过这个限制,它可以创建一个只有在运行时才知道的类型的数组,如下所示:

private Node[] next = (Node[]) Array.newInstance(Node.class, R);

【讨论】:

  • 如果我仍然想要非静态内部类中的 'Node[] next' 怎么办?
  • @Peterxwl 您可以通过以下方式欺骗编译器:private Node[] next = (Node[]) Array.newInstance(Node.class, R); 我会将其添加到答案中。
猜你喜欢
  • 2011-08-13
  • 2010-09-20
  • 1970-01-01
  • 2012-12-31
  • 1970-01-01
  • 2012-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多