I can't understand primitive-wrapper overhead with generics.
ex.
In Data Structure below, Why 24 byte Overhead isn't added to each item, instead it's added once for N inputs.
Question in other way, Why the overall memory space isn't 96N instead of 24 + 72N or why 24 added once.
public class GenericMysteryBox<Item> { // 16(object overhead)
private Node first; // 8 (reference)
private class Node { // 16(object overhead)
// 8 (inner class overhead)
private Item item; // 8 (reference to Integer)
// 24(Integer)
private Node next; // 8 (reference)
private Node prev; // 8 (reference)
} // -------
// 24 + 72N ~ 72N
}
Because the class declaration for Node (while an inner class) isn't mutable between instances. That is, every instance of GenericMysteryBox contains a Node that (after type erasure) has an Object reference and two Node references.
This is exactly the same behaviour as if Node were declared as a non-private non-inner class (ignoring the visibility of Node).
Consider,
class Node<Item> {
private Item item;
private Node next;
private Node prev;
}
public class GenericMysteryBox<Item> {
private Node<Item> first;
}
Related
I'm writing my own singly-linked list class for an assignment. I originally had my Node class in the root directory inside its own java file, but it assigns the generic T to obj, so it looks like it has to be nested inside SLList<T>.
My question (unrelated to the assignment): Is there a way to extract the Node class from the outer class, or must it be defined inside the outer class because it inherits the assignment?
public class SLList<T> {
Node head; // Front of the queue
Node tail; // Back of the queue
int count; // The number of elements in the queue
public class Node {
T obj; // The stored object in this node.
Node next; // The reference to the next object, null if final element.
}
...
...
...
If I create Node in an outer class, I run into the following error:
...
...
public T remove() {
// If empty, just return null:
if (count == 0)
return null;
// Set
T obj = head.obj; // ERROR: Object cannot be converted to type T.
head = head.next;
if (--count == 0)
tail = null;
return obj;
}
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.
Can a variable be declared in java using the name of a subclass? I found this piece of code about linked lists very confusing. See, how the head of the list has been declared. Can someone please explain?
class LinkedList
{
Node head; // head of list
/* Linked list Node*/
class Node
{
int data;
Node next;
// Constructor to create a new node
// Next is by default initialized
// as null
Node(int d)
{
data = d;
}
}
}
Yes, an object can indeed contain a reference to another object of the same type as an instance member.
For example, this is the standard class definition of a Linked List Node:
class Node {
int value;
Node next;
... // instance methods follow
}
You have the current node which must point to a reference of the next node in the linked list.
I have this bit of code and it keeps saying that it cannot create a generic array, but, I don't have a generic in my Node class, just an Object field. The Node class is an inner class. Why is it doing this?
public class TernarySearchTrie<E> implements TrieInterface<E> {
private Node[] root = new Node[256];
private int size = 0;
private class Node {
char c;
Node left, mid, right;
Object value;
}
}
Add the static modifier to Node class:
private static class Node {
char c;
Node left, mid, right;
Object value;
}
Without static, it depends of the TernarySearchTrie class, that have generics.
What you do in the problematic new Node[256] is actually TernarySeachTrie<E>.Node[256]. One solution is to use raw type:
Node[] root = TernarySearchTrie.Node[256];
Of course the compiler gives you a warning for this.
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.