I have a simple class in my Java program that models a BST of generic types. In this class there is an inner class that models the nodes of the BST.
public class Tree<T extends Comparable<T>> {
private class TreeElement {
private T element;
private TreeElement left = null;
private TreeElement right = null;
public TreeElement(T element){
this.element=element;
}
}
public TreeElement root=null;
public void insert(T element) {
if (root==null){
root=new TreeElement(element);
return;
}
//More Code here that is not relevant
}
}
Tree tree = new Tree();
tree.insert(5);
After inserting an Integer-Element into my Tree, I get the following Tree object (from debugger):
tree = {Tree#1147}
root = {Tree$TreeElement#1157}
element = {Integer#1155} 5
left = null
right = null
this$0 = {Tree#1147}
root = {Tree$TreeElement#1157}
element = {Integer#1155} 5
left = null
right = null
this$0 = {Tree#1147}
This would go on for as long as I keep clicking, so its an recursive reference to itself.
My questions are:
Where does the this$0-reference to itself come from?
How do I avoid it?
From my understanding, my Tree Object should only have a root Object that has 3 Attributes (element, left, right).
Where does the this$0-reference to itself come from?
It comes from the class being non-static.
How do I avoid it?
This reference is what enables your code to reference tree.this. You cannot get rid of it, unless you are willing to supply tree.this to the method that uses it through some alternative way (e.g. by passing it as a parameter all the time).
Once you figure out how to not reference tree.this from your code, making TreeElement class static would get rid of the hidden reference to Tree.
It's not a 'recursive reference to self'. It's a non-recursive reference to the instance of the outer class via which the inner-class object was created. You can get rid of it by changing the inner class to static, but this will cause other code problems if you access members of the outer class from within it. Such as tree.this.
This is not a problem, so you don't need to solve it.
Related
I need a doubly linked list that can work on different node implementations. Note that I do not want nodes that contain generic data, like DoublyLinkedNode<T>, but something like DoublyLinkedList<N extends DoublyLinkedNode<T>>.
To be precise, I use the list in the general case with standard nodes, but in other parts of my program I need nodes with additional fields. So I implemented the general node as
public class DoublyLinkedNode<T> {
DoublyLinkedNode<T> before, after;
T value;
}
and the special type as
public class DoublyLinkedSpecialNode<T, S> extends DoublyLinkedNode<T> {
S specialValue;
}
Now in my DoublyLinkedList implementation I want to be able to handle both cases at one, because all the code basically fiddles around with the pointers that are obviously common to both implementations.
This gives a few requirements:
1) When I use the special node, I want to be able to return it as the DoublyLinkedSpecialNode type to be able to access the additional fields.
2) The list must use a DoublyLinkedNode type to access the pointers of the nodes.
3) The list is assigning the pointed-to nodes to other nodes, e.g. head = node.after;, so the type of the pointers in the special node must be the same as the type in the list.
Extending the list makes no sense because then I could not change the return type of the methods. Therefore I tried two ideas without success:
The already mentioned solution: Generic node type that extends from DLN
The list would look like this:
public class DoublyLinkedList<T, N extends DoublyLinkedNode<T>> {
N head, tail;
N tail() {
return tail; // OK
}
void remove(N node) {
if (head == node) {
head = node.after; // Type error
}
...
This solution conflicts with requirement 3), because in the list the type is an N that extends from DLN, but in the node implementation N the pointer is of the type of the base class/interface DLN (the pointer type could theoretically be more general than N).
Base DLN instead of generics
In this case the list works on the base class node and accepts the subclasses because of polymorphism:
public class DoublyLinkedList<T> {
DoublyLinkedNode<T> head, tail;
DoublyLinkedNode<T> tail() {
return tail;
}
void remove(DoublyLinkedNode<T> node) {
if (head == node) {
head = node.after; // OK
}
...
But tail() can only return nodes as the general type, conflicting with 1). I would prefer not to use casting, because I assume it's bad practice (?) but also because the implementation is performance critical. There surely is a better way?
I found another solution that is okay-ish, not very performant but more elegant than the last solution.
The idea ist to use only one type of nodes, and wrap the varying content in a generic container. The DLN code looks like this:
public class DoublyLinkedNode<C> {
DoublyLinkedNode<C> before, after;
C content;
public static class ValueContent<T> {
T value;
}
public static class ValueSpecialContent<T, S> extends ValueContent<T> {
S specialValue;
}
}
The list implementation then looks something like this:
public class DoublyLinkedList<C> {
DoublyLinkedNode<C> head, tail;
public DoublyLinkedNode<C> head() {
return head;
}
void remove(DoublyLinkedNode<C> node) {
if (head == node) {
head = node.after;
...
And I can access the special field from the calling class like this:
DoublyLinkedList<SpecialContent<SpecialType>> list;
SpecialType s = list.head().content.specialValue;
There is some overhead because each node has to instantiate that container class, but I think it's still better than casting. I have to check the performance impact.
So, let's say we have these two classes.
public class Main<T extends Comparable<T>> {
public List<T> toList(T t){
Node n = new Node();
n.value = t; //This assignment1 gives no issues.
List<T> list = new List<T>();
list.add(n.value); //This assignment2 gives a type error.
return list;
}
}
class Node <T extends Comparable<T>> {
T value = null;
}
So, why does assignment1 go through without a type error, while assignment2 gives me the following error:
add (T) in List cannot be applied to (java.lang.Comparable)
It disappears when I do:
list.add((T)n.value);
But I would like to understand the reason first to figure out if above solution is the correct one.
EDIT: For now, I should specify that the code that uses these classes are Integer objects. So, I as the developer can assume that the T types are the same. But I am not sure if the code has some underlying routine that can change the values during casting.
Node n = new Node();
should be
Node<T> n = new Node<T>();
If you ever refer to Node without <something> after it, you are telling the compiler to ignore all type checking on Node. This will give you warnings, as it should.
I've two questions that relates to the following code (Linked Bag):
public class LinkedBag<Item> implements Iterable<Item> {
private Node first; // beginning of bag
private int N; // number of elements in bag
private class Node {
private Item item;
private Node next;
}
and this one
public class Bag<Item> implements Iterable<Item> {
private Node<Item> first; // beginning of bag
private int N; // number of elements in bag
// helper linked list class
private static class Node<Item> {
private Item item;
private Node<Item> next;
}
What's the difference between Node<Item> and Node here? both implementations are generic, so how Node and Node<Item>differ here ?
What's the meaning of static in the second version, why is it crucial ? ( doesn't compile without static).
Thanks !
If your nested class is not static, then it's an inner class, and the enclosing class's type parameter Item is in scope. However, if your nested class is static, then the enclosing class's type parameter is not in scope, because that type parameter has to do with an instance of the enclosing class, which is not relevant for a static nested class.
Here, the static class Node declares its own Item type parameter. It could have declared any other name and it would have been equivalent. You should not receive a compiler error using Node<Item> in your second case (with the static class); that is legal.
What's the difference between Node<Item> and Node here?
Adding a generic parameter is necessary because Java prohibits static inner classes of generic types from referencing type parameters of their outer types.
What's the meaning of static in the second version?
static means that Node instances do not get a reference to their parent class, and can be created outside of its context if it is necessary. It is not exactly "crucial", but shrinks your node by a third (two references vs. three references), which is an advantage.
If a nested class is not static (called an inner class), it means that every instance belongs to an instance of the enclosing class. Therefore in the first example, a Node instance belongs to a LinkedBag<Item>, so it already has a generic type Item (from LinkedBag<Item>).
An instance of a static nested class does not belong to an instance of the enclosing type, so it does not get the generic type parameter from an enclosing instance - you need to give it its own generic parameter.
Looking at the source code for the various Collection and Map implementations in the standard Java collections framework, you can see that both approaches to Node classes (static and non-static) are commonly used.
Is it a design flaw to have a static final variable in a generic class? Consider the class below, all references to Node.SOIL give rise to warnings. What is a good way of going about solving this problem?
public class Node<E> {
private static int nodeCounter = 0;
#SuppressWarnings({ "unchecked", "rawtypes" })
public static final Node SOIL = new Node(null, null); // <-- HERE
public static void resetSOIL(){
SOIL.children = null; // <-- HERE
}
private Node<E> parent;
private Set<Node<E>> children;
protected Set<Node<E>> isomorphs;
private E data;
private int id;
public Node(Node<E> parent, E data){
this.parent = parent;
this.data = data;
this.id = ++nodeCounter;
}
public boolean isRoot(){
return (this.getParent() == SOIL);
}
// utility methods
....
}
You've defined a type Node<E> which represents a node in a tree of E's. For example, Node<Integer> is a node in a tree of Integers, and Node<String> is a node in a tree of Strings.
Now you want a variable SOIL that contains all the roots of these various trees of different types (hehe, soil, I get it now). Set aside the static field issue for now. What should the class of SOIL be? In other words, how do we declare and create the SOIL instance?
Node</*something1*/> SOIL = new Node</*something2*/>(null, null);
Since SOIL is going to have children that are Node<Integer> and Node<String> then it has to be something like Node<?> or Node<Object>. You can't instantiate an object using a wildcard type argument, so the best you can do is something like this:
Node<?> SOIL = new Node<Object>(null, null);
(If you use the Java 7 diamond construct new Node<>(...) it ends up using Object in this case anyway.)
The problem is, this still doesn't work. The way the Node<E> type is defined is as a homogeneous tree of E's. But one subtree of SOIL is a tree of Integers and another subtree is a tree of Strings, so SOIL wants to be a heterogeneous tree. Therefore, SOIL cannot be a Node<E> for any E.
At least, not in a type-safe fashion. You could write the code to do this, but you'd have to add some casts, and you'd get unchecked warnings. These warnings would tell you that this approach isn't working. For example, consider some code that takes a Node<E> and operates on all of its siblings (that is, the other children of its parent). Some code that took a Node<Integer> could call this and end up with a bunch of instances of Node<String> and start throwing ClassCastExceptions.
You might consider making SOIL a Set<Node<?>> and not making it be the parent of all the roots. You could make it a static field somewhere, but make it private.
It's not a design flaw to have a static final variable. The warning appears because you are declaring an instance of a generic type without providing a type parameter:
public static final Node SOIL = new Node(null, null); // <-- HERE
when the compiler is expecting something like:
public static final Node<SomeType> SOIL = new Node<SomeType>(null, null);
You could use this to avoid suppressWarnings and it works well:
private static final Node<Object> SOIL = new Node<Object>(null, null);
To answer to your other question:
Is it a design flaw to have a static final variable in a generic class?
No itsnt, it is even a good common practice to use it as default for null variables of type Node, aka the NULL object in Effective Java Programming
I need to implement a B-Tree for University:
I have an "outer" class B-Tree with attributes root and _degree. The class to represent the nodes is implemented as a static-member class:
public class BTree<E> {
private Node<E> root;
// the minimal degree
private int degree;
public BTree(int degree) {
if (degree < 2) {
throw new IllegalArgumentException();
}
this.degree = degree;
}
// other stuff
private static class Node<T> {
T[] elements = (T[])new Object[degree * 2 - 1];
Node<T>[] children = (Node<T>[])new Object[degree * 2];
int size = 0;
}
}
So, now my problem is: As I implemented the Node class as a static member class, I can't access the degree attribute of the outer class.
Now I have to choices:
Make the Node class an inner class (non-static member class) OR
Create a constructor for the Node class and pass the degree in every time I need to construct a Node.
What would be the best choice? Making it an inner class would mean the Nodes would all have a reference to the Btree (outer class), but making it a static member class would mean I would have to pass the degree in every time.
I would keep it static and pass degree in. That way you ensure that Node cannot know any details about BTree.
If it were me, I'd have the Node class public so I could reuse it in other containing data structures, but that's just me. In that case, I'd have to pass the degree through the constructor, and that's OK with me too. I don't like the idea of inner classes manipulating the members of enclosing classes. I feel it makes the classes too tightly bound to each other. I know sometimes it's appropriate, but I avoid when I can and this seems an easily avoidable case.
There are arguments to make it static, because it decouples the classes.
But I think a BTree.Node is a node from a particular BTree. It doesn't make sense to go and create a bunch of Nodes (with random degrees). You can't have a Node, but no Tree. Thus, I say non-static.