Reputation: 89
I was trying to implement an R-way Trie Symbol Table, but meanwhile the implementation I have faced an unusual issue or I was not able to wrap head around this. Let me explain the issue I am facing:
package edu.nraj.dsalgo.rwaytrie;
public class RWayTrieST<Value> {
private static final int R = 256;
private Node root = new Node();
private class Node{
private Object value;
private Node[] next = new Node[R];
}
public static void main(String[] args) {
}
}
in this code block one can clearly see that I am creating an internal private class
private class Node{ ... }
But now the java se8 compiler shows an issue for the
private Node[] next = new Node[R];
saying that arrays of generic types not allowed. Node
which I already happen to know that Java doesn't allow a generic type array.
But here the compiler stop throwing the error if I make this Private Node class
a static class.
package edu.nraj.dsalgo.rwaytrie;
public class RWayTrieST<Value> {
private static final int R = 256;
private Node root = new Node();
private static class Node{
private Object value;
private Node[] next = new Node[R];
}
public static void main(String[] args) {
}
}
Can someone please explain this behavior down to its root cause so I can wrap my head around this.
Upvotes: 2
Views: 149
Reputation: 11949
If think the reason lies in the hidden details:
public class RWayTrieST<Value> {
private static final int R = 256;
private Node root = new Node();
private class Node{
private Object value;
private Node[] next = new Node[R];
}
}
Is actually:
public class RWayTrieST<Value> {
private static final int R = 256;
private Node root = new Node();
private class Node<Value>{
private final RWayTrieST<Value> $PARENT;
private Object value;
private Node[] next = new Node[R]; // and so Node is Node<Value> by this.
}
}
$PARENT
is a synthetic field (although that's not the exact name) the compiler adds to allow call to the parent non static methods. If the parent class contains generics, then the type of the $PARENT
is the RWayTrieST<Value>
.
And since Value is from the class declaration, it needs to be passed down to instance as well:
private static class Node<Value>
And so on in declaration, hence new Node<Value>[R]
.
If you want to fix that:
static class
as you were doing.ArrayList
.Node
class static
and add a private field RWayTrieST<?>
. You will probably have other problems.Upvotes: 0
Reputation: 270980
If you make your inner class static, it basically makes Node
not care about the generic parameter Value
. If Node
is not static, Node
then "belongs to instances of RWayTrieST
", just like any other non-static member. This means that the Node
of an instance of RWayTrieST<String>
will be a different type than the Node
of an instance of RWayTrieST<Integer>
.
This is as if Node
itself has a generic parameter, isn't it? RWayTrieST<String>.Node
and RWayTrieST<Integer>.Node
are entirely different types (at compile time, at least), just like ArrayList<String>
and ArrayList<Integer>
.
According to here, you can't create arrays of type with generic parameters, because something like this could happen if this were allowed:
RWayTrieST<String> foo = ...;
RWayTrieST<Integer> bar = ...;
Object[] stringArray = foo.new Node<String>[]; // compiler error, but pretend it's allowed
stringArray[0] = foo.new Node<String>(); // OK
stringArray[1] = bar.new Node<Integer>(); // An ArrayStoreException should be thrown,
// but the runtime can't detect it, because generic types are erased.
Upvotes: 0
Reputation: 12463
In the simplest way I can put this, when you make a class generic, all its inner classes are also generic because they share the outer class information. As you probably already know, the difference between
public class RWayTrieST<Value> {
private class Node {}
}
and
public class RWayTrieST<Value> {
private static class Node {}
}
is that, in the former, Node is an inner class and instances of Node
have to be tied to instances of RWayTrieST
. So if you have foo = New RWayTrieST<String>()
and you have bar = foo.new Node()
, then to the compiler, bar
's type is effectively RWayTrieST<String>.Node
because the generic information of the outer class is necessary.
In the latter however, instances of Node
are not tied to instances of RWayTrieST
because it is a static inner class. So Node
does not share the outer class generic info which means it is not generic.
Upvotes: 1