Java create map of Generic Objects - java

I have a Node class:
public class Node<T extends MySuperClass> {
private T data;
private Node<? extends MySuperClass> parent;
private List<Node<? extends MySuperClass>> children;
public Node(T data, Node<? extends MySuperClass> parent, List<Node<? extends MySuperClass>> children) {
this.data = data;
this.parent = parent;
this.children = children;
}
public T getData() {
return data;
}
public Node<? extends MySuperClass> getParent() {
return parent;
}
public List<Node<? extends MySuperClass>> getChildren() {
return children;
}
public void setData(T data) {
this.data = data;
}
public void setParent(Node<? extends MySuperClass> parent) {
this.parent = parent;
}
public void setChildren(List<Node<? extends MySuperClass>> children) {
this.children = children;
}
}
I need to create a map of Generic Node defined above. I have to write something like this
List<Map<Long, Node<? extends MySuperClass>>> tree = new ArrayList<Map<Long, Node< extends MySuperClass>>>();
When I try to add an instance of map to the list
public MyClass extends MySuperClass{
}
Map<Long, Node<MyClass>> myMap = new HashMap<Long,Node<MyClass>>();
tree.add(myMap);
The Compiler gives me the following message:
The method add(Map<Long,Node<? extends MySuperClass>>) in the type List<Map<Long,Node<? extends MySuperClass>>> is not applicable for the arguments (Map<Long,Node<MyClass>>)
Syntactically it is correct. I Can't understand why it doesn't work.

Your Map should be defined the same type as your List.
This is because the List expects a type of Map<Long, Node<? extends MySuperClass>>. The type Node<? extends MySuperClass> and Node<MyClass> are not the same.
From http://docs.oracle.com/javase/tutorial/java/generics/inheritance.html
Note: Given two concrete types A and B (for example, Number and
Integer), MyClass<A> has no relationship to MyClass<B>, regardless of
whether or not A and B are related. The common parent of MyClass<A>
and MyClass<B> is Object.
Note : I add to add a default constructor to your Node class to get the next four lines to compile since I didnt want to type in the params for the other constructor.
List<Map<Long, Node<? extends MySuperClass>>> tree = new ArrayList<Map<Long, Node<? extends MySuperClass>>>();
Map<Long, Node<? extends MySuperClass>> myMap = new HashMap<Long, Node<? extends MySuperClass>>();
myMap.put(1L, new Node<MyClass>());
tree.add(myMap);

Related

Java generics self-reference: is it safe?

I have this simple interface:
public interface Node<E extends Node<E>>
{
public E getParent();
public List<E> getChildren();
default List<E> listNodes()
{
List<E> result = new ArrayList<>();
// ------> is this always safe? <-----
#SuppressWarnings("unchecked")
E root = (E) this;
Queue<E> queue = new ArrayDeque<>();
queue.add(root);
while(!queue.isEmpty())
{
E node = queue.remove();
result.add(node);
queue.addAll(node.getChildren());
}
return result;
}
}
I see that this is always an instance of Node<E> (by definition).
But I can't imagine a case where this is not an instance of E...
Since E extends Node<E>, shouldn't Node<E> also be equivalent to E by definition??
Can you give an example of an object that's an instance of Node<E>, but it's not an instance of E??
Meanwhile, my brain is melting...
The previous class was a simplified example.
To show why I need a self-bound, I'm adding a bit of complexity:
public interface Node<E extends Node<E, R>, R extends NodeRelation<E>>
{
public List<R> getParents();
public List<R> getChildren();
default List<E> listDescendants()
{
List<E> result = new ArrayList<>();
#SuppressWarnings("unchecked")
E root = (E) this;
Queue<E> queue = new ArrayDeque<>();
queue.add(root);
while(!queue.isEmpty())
{
E node = queue.remove();
result.add(node);
node.getChildren()
.stream()
.map(NodeRelation::getChild)
.forEach(queue::add);
}
return result;
}
}
public interface NodeRelation<E>
{
public E getParent();
public E getChild();
}
An easy example to illustrate the problem: a node of a different type of node:
class NodeA implements Node<NodeA> {
...
}
And:
class NodeB implements Node<NodeA> {
...
}
In this case, E root = (E) this would resolve to NodeA root = (NodeA) this, where this is a NodeB. And that's incompatible.
Without <E extends Node<E>>, you could have either of these cases:
Node<Integer>
where the generic type isn't a Node at all, or
Node<DifferentNode>
where the generic bounds don't match.
That said, it's not typical to see a bound this way, as Node<E> is expected to be a node that contains some value of type E, and children would be a List<Node<E>>, not a List<E>.
The problem is not in E root = (E) this. It might work well until you start iterating through result of listNodes().
That example demonstrates where exactly ClassCastException will be thrown:
public interface Node<E extends Node<E>> {
List<E> getRelatedNodes();
default List<E> getAllNodes() {
List<E> result = new ArrayList<>();
result.add((E) this); //<--that cast is not a problem because of type erasure
return result;
}
}
class NodeA implements Node<NodeA> {
public NodeA() {
}
#Override
public List<NodeA> getRelatedNodes() {
return null;
}
}
class NodeB implements Node<NodeA> {
private List<NodeA> relatedNodes;
public NodeB(List<NodeA> relatedNodes) {
this.relatedNodes = relatedNodes;
}
#Override
public List<NodeA> getRelatedNodes() {
return relatedNodes;
}
}
Execute:
List<NodeA> nodes = new NodeB(Arrays.asList(new NodeA())).getAllNodes(); //according to generic it is list of NodeA objects
for (NodeA node : nodes) { //ClassCastException will be thrown
System.out.println(node);
}
With this sort of situation it is often useful to have a getThis method that (by convention) returns this.
I would do the following
public interface Node<E extends Node<E, R>,
R extends NodeRelation<E, R>>
{
public List<R> getParents();
public List<R> getChildren();
public List<E> listDescendants() ;
}
public interface NodeRelation<E extends Node<E, R>,
R extends NodeRelation<E, R>>
{
public E getParent();
public E getChild();
}
abstract class ANode<E extends ANode<E,R>,
R extends ARelation<E,R>>
implements Node<E,R> {
abstract protected E getThis() ;
public List<E> listDescendants()
{
List<E> result = new ArrayList<>();
E root = getThis() ;
...
return result;
}
}
abstract class ARelation<E extends ANode<E,R>,
R extends ARelation<E,R>>
implements NodeRelation<E,R> {
}
class CNode extends ANode<CNode, CRelation> {
public CNode getThis() { return this ; }
...
}
class CRelation extends ARelation<CNode, CRelation> {
...
}
Although I might not bother with having both abstract class and interface layers.

wildcard and generic from TreeItem

I have following class:
class TreeItem<T extends TreeItem<?>>{
private final ObservableList<T> childs;
private T parent;
public void addChild(T unit){
childs.add(unit);
unit.setParent(this);
}
public <T> void setParent(T parent){
this.parent = parent;
}
}
I get this message on setParent:
Incompatible types.
Required: T
Found: T
How can i fix this?
Rewrite this:
public <T> void setParent(T parent){
this.parent = parent;
}
With this:
public void setParent(T parent){
this.parent = parent;
}
Also I would suggest to remove the wildcare in the class name declaration, as the code would not compile.
So replace this:
class TreeItem<T extends TreeItem<?>>
With this:
class TreeItem<T extends TreeItem>
You have a final variable in your class. So it should be initialized either in constructor or inline. As long as you use generic variable and generic type is resolved when you instantiate a new object, the right way to do is to initialize it in constructor like this:
public TreeItem(ObservableList<T> childs) {
this.childs = childs;
}
When you are done with the above proposed changes you may notice that the compiler warns you with the message: Unchecked call to 'setParent(T)'. That means that the compiler does not guarantee the code is safe during runtime and possible heap pollution may occure.
I will illustrate it with an example. The following code while running ends up with ClassCastException as we set parent variable with the type which is not T (it is possible due to type erasure).
class ChildTreeItem<T extends TreeItem> extends TreeItem<T> {
public ChildTreeItem(ObservableList childs) {
super(childs);
}
}
public class TreeItem<T extends TreeItem>{
private final ObservableList<T> childs;
private T parent;
public TreeItem(ObservableList<T> childs) {
this.childs = childs;
}
public void addChild(T unit){
childs.add(unit);
unit.setParent(this);
}
public void setParent(T parent){
this.parent = parent;
}
public T getParent() {
return parent;
}
public static void main(String[] args) {
ChildTreeItem<ChildTreeItem> treeItem =
new ChildTreeItem<>(new ObservableSequentialListWrapper<>(new ArrayList<>()));
TreeItem<ChildTreeItem> parentItem =
new TreeItem<>(new ObservableSequentialListWrapper<>(new ArrayList<>()));
parentItem.addChild(treeItem);
List<ChildTreeItem> itemList = new ArrayList<>();
itemList.add(treeItem.getParent()); //<------------------- Heap pollution
ChildTreeItem childTreeItem = itemList.get(0); //<-------- ClassCastException
}
}
The possible solution to this problem is to not parametrize the variable parent but to make it TreeItem type:
public class TreeItem<T extends TreeItem>{
private final ObservableList<T> childs;
private TreeItem parent;
public TreeItem(ObservableList<T> childs) {
this.childs = childs;
}
public void addChild(T unit){
childs.add(unit);
unit.setParent(this);
}
public void setParent(TreeItem parent){
this.parent = parent;
}
public TreeItem getParent() {
return parent;
}
}
Hope this helps.
Since you have define already in your class level of Generic type. It is not clear why you put before your setParent function. But let's assume you want to define a generic type in function level, then when you call it, you need to specify the type
Ex:
TreeItem<String> treeItem = new TreeItem<String>();
treeItem.<String>setParent("something");

Implement generic vertex and edge classes

I would like to implement generic graph classes. These are what I came up with:
public abstract class VertexBase<V extends VertexBase<V, E>, E extends EdgeBase<V, E>> {
public final HashMap<V, E> inEdges = new HashMap<>();
public final HashMap<V, E> outEdges = new HashMap<>();
}
public abstract class EdgeBase<V extends VertexBase<V, E>, E extends EdgeBase<V, E>> {
public final V fromVertex;
public final V toVertex;
public EdgeBase(V from, V to) {
fromVertex = from;
toVertex = to;
from.outEdges.put(to, get());
to.inEdges.put(from, get());
}
protected abstract E get();
}
Now the problem is that I have to implement Edge::get everywhere:
#Override
protected Edge get() {
return this;
}
And the compiler complains that I am calling overridable method in the constructor.
Is there a way to better implement these?
When you implement new class that extends EdgeBase, you need to replace all E type to Edge and Edge must be extends EdgeBase < V, Edge >, for example:
public class EdgeBaseImpl<V extends VertexBase<V, Edge>> extends EdgeBase<V, Edge> {
...
#Override
protected Edge get() {
return this;
}
}

comparing generic type E node objects

I have a class
private class BSTNode<E extends Comparable<E>> implements Comparable<E> {
BSTNode<E> left, right;
E data;
with constructor and compairTo method
but when I want instantiate the BSTNode class I face problem.
public class BST {
private BSTNode<E> root;
/* Constructor */
public BST() {
root = new BSTNode<E>();
}
how should I use BSTNode in my BST class ? Thanks
Something on these lines (not full fledge or concrete):
public class BST<E extends Comparable<E>>
{
private class BSTNode<E extends Comparable<E>> implements Comparable<E> {
BSTNode<E> left, right;
E data;
#Override
public int compareTo(E o) {
return 0;//implement method here
}
}
private BSTNode<E> root;
public BST() {
root = new BSTNode<E>();//while comparing you would need to case E to comparable and call compareTo method
}
public static void main(String[] args)
{
BST<String> messages = new BST<String>();
}
}
Your class header means that your BTSNode may only be instantiated with classes E which implement the Comparable interface.
As such, you should be able to use it as below:
public class BST {
private BSTNode<Integer> root;
/* Constructor */
public BST() {
root = new BSTNode<Integer>();
}
}
Integer may be replaced with any of the other implementing classes listed here or your even own custom implementation.

JAVA: Generic type compile time constant

I have an abstract generic class which requires a numeric constant to initialize an array. I know the size of array at compile time when I use that generic class. Is there any way to implement this?
abstract class Node<T, MagicN> {
private T parent = null;
private T[] child = (T[]) new Object[MagicN];
//some methods that rely on the initialized array.
}
final class ConcreteNode extends Node<ConcreteNodeType, 2> {
}
The class ConcreteNode has 2 children in this example.
You can't use a Generic as a template. As Java's code optimisation is done at runtime, there is little reason to have such compile time inlining.
abstract class Node<T extends Node> {
private final T parent;
private final T[] child;
Node(T parent, int size) {
this.parent = parent;
child = (T[]) new Object[size];
}
//some methods that rely on the initialized array.
}
final class ConcreteNode extends Node<ConcreteNode> {
ConcreteNode(ConcreteNode parent) {
super(parent, 2);
}
}
You can't have values instead of a generic type (or you should have to create a class for each value you may use...)
I think the best in your case would to have a constructor that takes this value as a parameter for example :
abstract class Node<T> {
private T parent = null;
private int MagicN = 0;
private T[] child = null;
protected Node(int MagicN)
{
this.MagicN = MagicN;
this.child = (T[]) new Object[MagicN];
}
//some methods that rely on the initialized array.
}
final class ConcreteNode extends Node<ConcreteNodeType> {
public ConcreteNode()
{
super(2);
}
}
In terms of performance, there is no difference between what you are trying to do and this example since your child array is initialized in an object context and not a static one.
Why not do it this way?
abstract class Node<T> {
private T parent = null;
private T[] child;
public Node(int childCount) {
child = (T[]) new Object[childCount];
//some methods that rely on the initialized array.
}
final class ConcreteNode extends Node<ConcreteNodeType> {
public ConcreteNode()
{
super(2);
}
}

Categories

Resources