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
Related
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>>
I want to implement an abstract Hierarchy class. Any Hierarchy object should have a parent (could be null) and a set of children, both of the exact same type as the concrete implementation of Hierarchy. Can this be done with generics, and if not is there any mechanism to enforce this relationship?
Here's what I was thinking so far, but there are issues:
public abstract class Hierarchy<T extends Hierarchy<T>> {
private T parent;
private Set<T> children;
public T getRoot() {
if( parent == null ) {
return this;
} else {
return parent.getRoot();
}
}
}
The problem is with return this. It gives a compile error because this is of type Hierarchy, not T. I can't cast it, because I don't actually guarantee that this is of type T. The following declaration would compile just fine:
public class B extends Hierarchy<B> {...}
public class A extends Hierarchy<B> {...}
So is there any way I can disallow A extends Hierarchy<B> declarations?
So is there any way I can disallow A extends Hierarchy
declarations?
No, it is not possible.
You can do what you want with something like this:
public abstract class Hierarchy<T> {
private T parent;
private Set<T> children;
public static <E extends Hierarchy<E>> E getRoot(E x) {
while (x.parent != null) {
x = x.parent;
}
return x;
}
}
Bound mismatch: The type Integer is not a valid substitute for the bounded parameter <Item extends Comparable<Item>> of the type BTNode<Item>
This is where I am getting the error:
public class BinaryTree<Integer> {
private BTNode<Integer> root;
//...
}
This is the class I am using:
public class BTNode<Item extends java.lang.Comparable<Item>> implements java.lang.Comparable<BTNode<Item>> {
private Item data;
//...
}
I think the Integer wrapper should satisfy the condition <xx extends Comparable<xx>>.
Is my understanding wrong? Can you please tell me what I am doing wrong here?
Just for the record, I am using java.lang.Comparable and not my own implementation of Comparable.
Here is the issue:
public class BinaryTree<Integer> {
private BTNode<Integer> root;
}
The class parameter is named Integer. When declaring BTNode<Integer>, you are not referencing java.lang.Integer but the parameter instead.
I don't really know what you're trying to do, but one advice: better use one single letter to name your classes parameters. For example, no error occurs when using:
public class BinaryTree<T> {
private BTNode<Integer> root;
}
If you wanted root to really use the class parameter, then:
public class BinaryTree<T extends Comparable<T>> {
private BTNode<T> root;
}
Have a look at the following lesson: http://docs.oracle.com/javase/tutorial/extra/generics/index.html
I'm working on a project for class that involves generics.
public interface Keyable <T> {public String getKey();}
public interface DataElement extends Comparable<Keyable<DataElement>>, Keyable<DataElement>, Serializable {...}
public class Course implements DataElement {...}
public interface SearchTree<K extends Comparable<Keyable<K>> & Keyable<K>> extends Serializable {...}
public class MySearchTree implements SearchTree<Course> {
...
private class Node {
public Course data;
public Node left;
public Node right;
...
}
}
When trying to use the Course class within the declaration of MySearchTree, I receive a type argument error stating that "Course is not within the bounds of type-variable K". I spent a good amount of time trying to figure out what attributes Course might be lacking to make it not fit the bill, but came up empty.
Any ideas?
In MySearchTree the K of the base type is Course. So K must "extend" Comparable<Keyable<Course>> & Keyable<Course>. But it doesn't, it extends Comparable<Keyable<DataElement>> & Keyable<DataElement>.
I guess DataElement should be generified in a similar manner to Comparable or Enum.
public interface Keyable <T> {public String getKey();}
public interface DataElement<THIS extends DataElement<THIS>> extends Comparable<Keyable<THIS>>, Keyable<THIS>, Serializable {...}
public class Course implements DataElement<Course> {...}
public interface SearchTree<K extends Comparable<Keyable<K>> & Keyable<K>> extends Serializable {...}
public class MySearchTree implements SearchTree<Course> {
I have the concept of NodeTypes and Nodes. A NodeType is a bunch of meta-data which you can create Node instances from (a lot like the whole Class / Object relationship).
I have various NodeType implementations and various Node implementations.
In my AbstractNodeType (top level for NodeTypes) I have ab abstract createInstance() method that will, once implemented by the subclass, creates the correct Node instance:
public abstract class AbstractNodeType {
// ..
public abstract <T extends AbstractNode> T createInstance();
}
In my NodeType implementations I implement the method like this:
public class ThingType {
// ..
public Thing createInstance() {
return new Thing(/* .. */);
}
}
// FYI
public class Thing extends AbstractNode { /* .. */ }
This is all well and good, but public Thing createInstance() creates a warning about type safety. Specifically:
Type safety: The return type Thing for
createInstance() from the type
ThingType needs unchecked conversion
to conform to T from the type
AbstractNodeType
What am I doing wrong to cause such a warning?
How can I re-factor my code to fix this?
#SuppressWarnings("unchecked") is not good, I wish to fix this by coding it correctly, not ignoring the problem!
You can just replace <T extends AbstractNode> T with AbstractNode thanks to the magic of covariant returns. Java 5 added support, but it didn't receive the pub it deserved.
Two ways:
(a) Don't use generics. It's probably not necessary in this case. (Although that depends on the code you havn't shown.)
(b) Generify AbstractNodeType as follows:
public abstract class AbstractNodeType<T extends AbstractNode> {
public abstract T createInstance();
}
public class ThingType<Thing> {
public Thing createInstance() {
return new Thing(...);
}
}
Something like that should work:
interface Node{
}
interface NodeType<T extends Node>{
T createInstance();
}
class Thing implements Node{}
class ThingType implements NodeType<Thing>{
public Thing createInstance() {
return new Thing();
}
}
class UberThing extends Thing{}
class UberThingType extends ThingType{
#Override
public UberThing createInstance() {
return new UberThing();
}
}