Why can I not assign to this generic variable? - java

I'm trying to implement a tree such that the nodes are generic:
public class BinarySearchTree<U extends BinarySearchTree.Node, T extends Comparable<? super T>>
{
public U root;
...
public class Node {
T data;
U left;
U right;
public Node(T data) {
this.data = data;
left = null;
right = null;
}
}
}
But when I try to do an assignment in one of my methodsI get a "Expected U but found BinarySearchTree.Node:
public void display(U root) {
if (root != null) {
display(root.left); // gives compile time error
System.out.print(" " + root.data);
display(root.right); // gives compile time error
}
}

Since Node is not static, every Node instance belongs to a containing BinarySearchTree instance. But it is not possible with generics to specify to which one it belongs. So if you specify BinarySearchTree.Node it can belong to any BinarySearchTree. Since you also used a raw type (don't ignore the warnings!) it is not known what U is. Therefore, Java cannot check that root.left and root.right are of the same type, which is why you get the error.
You can fix the compile error by specifying the class as follows:
class BinarySearchTree<U extends BinarySearchTree<U,T>.Node, T extends Comparable<? super T>>
{ ... }
but this does not fix the underlying problem that the nodes can belong to any containing BinarySearchTree, which probably is not what you want.
If you really want use a generic node type, you could make it static you, so that it doesn't belong to containing instances anymore:
public static class Node<U,T>
{
...
}
But I question the need to have a generic node class in the first place. Usually, such nodes are considered an implementation detail and you want to have full control over creating them from within your class. That cannot work with a generic node because your class doesn't know what kind of nodes to instantiate.
So I would define your BinarySearchTree class as follows:
public class BinarySearchTree<T extends Comparable<? super T>>
{
private Node<T> root;
private static class Node<T>
{
T data;
Node<T> left;
Node<T> right;
}
...
}

You should rewrite the class definition to
public class BinarySearchTree<U extends BinarySearchTree<U, T>.Node, T extends Comparable<? super T>>

Related

Java Generic Type flexibility with subtype assignment

I have the following structure. A parent class:
public class MyTree<E extends MyTree<E>>{
List<E> children;
public MyTree(List<E> ls){
this.children = ls;
}
public void insert(E t){
this.children.add(t);
}
}
a child class:
public class SpecTree<E> extends MyTree<SpecTree<E>>{
private E value;
public SpecTree(E value){
super(new ArrayList<>());
this.value = value;
}
}
Now from main, I want to insert a tree into another tree.
SpecTree<Number> st = new SpecTree<>(0);
st.insert(new SpecTree<Integer>(2)); //incompatible type error
The SpecTree must be able to accept new children with values that are subtype of the current tree. For example, I should be able to insert a SpecTree<Integer> into SpecTree<Number>.
Is it possible to do without changing the structure of code and changing only the type parameters?
The error occurs because insert expects SpecTree<Number>, but we are giving it SpecTree<Integer>.
According to PECS, insert would be able to take both SpecTree<Number> and SpecTree<Integer> if it had took a SpecTree<? extends Number>. A producer of integers is a consumer of numbers.
That means changing E to SpecTree<? extends E>:
public void insert(E t)
Therefore:
class SpecTree<E> extends MyTree<SpecTree<? extends E>>
However, now the type argument SpecTree<? extends E> does not fit the bound specified in MyTree, which is E extends MyTree<T>, so we change that too:
class MyTree<E extends MyTree<? extends E>>

cannot initialize the type

I build a class 'AbstractTree' and create another class 'SearchTree' which extends 'AbstractTree'.
public class SearchTree<TreeNode> extends AbstractTree<TreeNode> {
TreeNode root;
public SearchTree(){
root=new TreeNode();
}
}
There is an error occured in the constructing method. It says that it cannot initialize the type TreeNode.
TreeNode is another class I build.
public class TreeNode<E> extends AbstractNode<E> {
E element;
TreeNode<E> parent;
ArrayList<TreeNode<E>> children;
public TreeNode(){
parent=new TreeNode<E>();
children=new ArrayList<TreeNode<E>>();
}
//...some other methods
}
Your declaration of SearchTree has an error. In fact public class SearchTree<TreeNode> extends AbstractTree<TreeNode> {is using TreeNode as a generic class Type parameter and not as the TreeNode class that you are intending to use here.
And so the generic type parameter that you called TreeNode is now hidding usage of the real TreeNode class. See attached image
Therefore I would change your SearchTree class the following way:
public class SearchTree<E> extends AbstractTree<TreeNode<E>> {
TreeNode<E> root;
public SearchTree()
{
root = new TreeNode<E>();
}
}

How can I paramaterize this Java generic?

I am building a generic binary tree class in Java. I have not worked with generics too much before, so I do not know if I am doing this properly. Here is some code followed by my question:
public class Node<T> {
T data;
Node<T> left, right;
//assume setters and getters
}
public class BinaryTree<T extends Comparable <T>> {
private Node<T> root;
//assume typical setter/getter and insert, delete, etc methods
public void inOrderTraversal() {
//create instance of the inorder class here and call its traverse() method.
}
}
//define a family of algorithms for preorder, inorder and postorder traversals
public interface BinaryTreeTraversal {
public void traverse();
}
//of course there will be a class for each type of traversal...
//in order, pre order, post order
class PreOrderTraversal extends BinaryTree implements BinaryTreeTraversal {
public void traverse() { traverse(super.getRoot() ); }
private void traverse(Node<T>) {
//the three lines of code this takes
}
}
So the problem I am having is that I keep getting errors saying missing type T, or unknown type T. So I tried changing the class heading it to
class PreOrderTraversal extends BinaryTree<T> implements BinaryTreeTraversal { }
and
class PreOrderTraversal extends BinaryTree<T extends Comparable<T>> implements BinaryTreeTraversal { }
and it did not work due to similar errors. What is a way that I can make this work? I am trying to apply a strategy pattern to the traversals. I just want to be able to have three types of traversals for any generic type. Any tips would be appreciated. Thank you.
private class PreOrderTraversal< T extends Comparable< T > > extends BinaryTree< T > implements BinaryTreeTraversal { ... }
For generic classes, the parameter and all its constraints go right next to the name of the class being defined. Unfortunately, that syntax was not chosen for generic methods, where the generic type parameters and constraints precede the return type.
your class PreOrderTraversal implements you generic class BinaryTree so here you need to define the type of T like
java
class PreOrderTraversal extends BinaryTree<Integer> implements BinaryTreeTraversal {
private void traverse(Node<Integer>) {
}
}
where Integer would by the type you are storing in the binary tree, now

Generic wildcard in Java

I'm writing a generic class:
public class Node<T> {
private Node<T> parent = null;
private List<? extends Node<T>> children = null;
public Node<T> getParent() {
return parent;
}
public void setParent(Node<T> parent) {
if(this.parent != null){
// Remove current parent's children references
this.parent.getChildren().remove(this);
}
// Add references
this.parent = parent;
parent.getChildren().add(this);
}
public List<? extends Node<T>> getChildren() {
return children;
}
}
I want some other class which subclass this Node. This code cannot be compiled with the error on line parent.getChildren().add(this);. Because I declared getChildren() with List<? extends Node<T>> as return type, and 'this' is type Node<T>.
Is there anyway to solve this?
Declare the list as:
List<Node<T>> children
You may still put instances of subclasses in the list.
If you leave it as an unknown type, the compiler can't ensure which class it is typed as. Eg it might be typed as SubClassA, but you're adding SubClassB and it has no way to know based on the declared type, which is all the compiler has to go on. At runtime, while the type of list and child might match, the compiler can't assert.

How come Java doesn't accept my LinkedList in a Generic, but accepts its own?

For a class assignment, we can't use any of the languages bultin types, so I'm stuck with my own list. Anyway, here's the situation:
public class CrazyStructure <T extends Comparable<? super T>> {
MyLinkedList<MyTree<T>> trees; //error: type parameter MyTree is not within its bound
}
However:
public class CrazyStructure <T extends Comparable<? super T>> {
LinkedList<MyTree<T>> trees;
}
Works. MyTree impleements the Comparable interface, but MyLinkedList doesn't. However, Java's LinkedList doesn't implement it either, according to this. So what's the problem and how do I fix it?
MyLinkedList:
public class MyLinkedList<T extends Comparable<? super T>> {
private class Node<T> {
private Node<T> next;
private T data;
protected Node();
protected Node(final T value);
}
Node<T> firstNode;
public MyLinkedList();
public MyLinkedList(T value);
//calls node1.value.compareTo(node2.value)
private int compareElements(final Node<T> node1, final Node<T> node2);
public void insert(T value);
public void remove(T value);
}
MyTree:
public class LeftistTree<T extends Comparable<? super T>>
implements Comparable {
private class Node<T> {
private Node<T> left, right;
private T data;
private int dist;
protected Node();
protected Node(final T value);
}
private Node<T> root;
public LeftistTree();
public LeftistTree(final T value);
public Node getRoot();
//calls node1.value.compareTo(node2.value)
private int compareElements(final Node node1, final Node node2);
private Node<T> merge(Node node1, Node node2);
public void insert(final T value);
public T extractMin();
public int compareTo(final Object param);
}
I assume your MyTree is the same as LeftistTree. The problem with the signature is that it doesn't implement Comparable<LeftistTree<? super T>>.
So the signature should be:
public class LeftistTree<T extends Comparable<? super T>>
implements Comparable<LeftistTree<? super T>>
The reason is that your MyLinkedList is not like a regular LinkedList. A regular LinkedList is of type: LinkedList<T> there are no bounds on T. You require with MyLinkedList that the parameter implement a Comparable of itself (or its superclass), but in fact LeftistTree was implementing a raw Comparable (or Comparable<?>) so the Comparable was not guaranteed to be related to the type.
Why does your linked list must accept a Comparable typed?
For a collection data structure, forcing your collection to only accept specific data type is very limiting.
If you would like to have a sorted linked list, it is better to accept any element and allow your linked list to accept a Comparator object. If you do not provide a Comparator, then you can rely on the natural ordering of the contained element if they are of Comparable typed.
Take a look at the SortedSet or SortedMap api signature for some example.

Categories