0

I'm sure this has been asked before but I am new to Java and unfamiliar with the exact terminology I'm looking for.

I have a BST class:

public class BinarySearchTree<T extends Comparable> {
    /* ... */
}

Then I wrote some tests for it:

public static void main(String[] args) {
    Integer[] integerItems = {1, 7, 8, 2, -1, -10, 100, 12, 32};
    String[] stringItems = {"jungi", "phil", "bob", "leslie", "tyler", "clarence"};
    Comparable[][] comparableLists = {integerItems, stringItems};

    for (Comparable[] list : comparableLists) {
        BinarySearchTree<>...
    }
}

I am confused at this step. How can I recover the types (String[], Integer[], etc.) from the list and use them as an argument? I want to have something like this:

for (Comparable[] list : comparableLists) {
    BinarySearchTree<typeOf(list)> root = new BinarySearchTree<typeOf(list)>();
    /* ... tests ... */
}

One option I found here was just to list out all the possible supported types. This seems really silly because I don't know all the supported types. Maybe these types will change, etc. but I had it hard-coded.

How can I deal with this best?

EDIT:

So just to be a little more specific, here is the BST implementation:

public class BinarySearchTree<T extends Comparable> {
    private T value;
    private BinarySearchTree<T> leftChild;
    private BinarySearchTree<T> rightChild;

    public BinarySearchTree() {

    }

    public BinarySearchTree(T v) {
        value = v;
        createChildren();
    }

    public void createChildren() {
        leftChild = new BinarySearchTree<T>();
        rightChild = new BinarySearchTree<T>();
    }

    public void insert(T v) {
        if (value == null) {
            value = v;
            createChildren();
        } else if (v < value) {
            leftChild.insert(v);
        }
        rightChild.insert(v);
    }

    public boolean valueExists(T v) {
        if (value == null) {
            return false;
        } else if (value == v) {
            return true;
        } else if (v < value) {
            return leftChild.valueExists(v);
        }
        return rightChild.valueExists(v);
    }

    public String toString() {
        String bstStringBuilder = "";

        if (value == null) {
            return "";
        }

        bstStringBuilder += leftChild + " ";
        bstStringBuilder += value + " ";
        bstStringBuilder += rightChild;
        return bstStringBuilder;
    }
}

If I use @OldCurmudgeon's suggestion the main() looks like this:

public static void main(String[] args) {
    Integer[] integerItems = {1, 7, 8, 2, -1, -10, 100, 12, 32};
    String[] stringItems = {"jungi", "phil", "bob", "leslie", "tyler", "clarence"};
    Comparable[][] comparableLists = {integerItems, stringItems};

    for (Comparable[] list : comparableLists) {
        BinarySearchTree<Comparable> root = new BinarySearchTree<Comparable>();

        for (Comparable item : list) {
            root.insert(item);
        }

        System.out.println(root);
    }
}

This produces the following compiler error:

BinarySearchTree.java:26: error: bad operand types for binary operator '<'
    } else if (v < value) {
                 ^
first type:  T
second type: T
where T is a type-variable:
  T extends Comparable declared in class BinarySearchTree
  BinarySearchTree.java:37: error: bad operand types for binary operator '<'
      } else if (v < value) {
                 ^
first type:  T
second type: T
where T is a type-variable:
  T extends Comparable declared in class BinarySearchTree
2 errors

Perhaps this is more helpful?

Community
  • 1
  • 1
eatonphil
  • 13,115
  • 27
  • 76
  • 133

3 Answers3

0

Generic method to the rescue!

Look:

class BinarySearchTree<T extends Comparable<T>> {
    void put(T item) {}
}

class Test {

    public static <T extends Comparable<T>> void putIntoATree(BinarySearchTree<T> tree, T[] items) {
        for (T item : items)
            tree.put(item);
    }

    public static void main(String[] args) {

        Integer[] integerItems = {1, 7, 8, 2, -1, -10, 100, 12, 32};
        BinarySearchTree<Integer> integerTree = new BinarySearchTree<>();
        putIntoATree(integerTree, integerItems);

        String[] stringItems = {"jungi", "phil", "bob", "leslie", "tyler", "clarence"};
        BinarySearchTree<String> stringTree = new BinarySearchTree<>();
        putIntoATree(stringTree, stringItems);

    }

}

Presence of arrays holding generified types, as in your example, usually forces a cast somewhere (or leaves 'unchecked' warning). That's why I've avoided using an array in my example.

One way to eliminate a cast and make code type-safe is to wrap array into a generic class which will make javac happy:

class BinarySearchTree<T extends Comparable<T>> {
    void put(T item) {}
}

class Test {

    public static <T extends Comparable<T>> void putIntoATree(BinarySearchTree<T> tree, T[] items) {
        for (T item : items)
            tree.put(item);
    }

    private static class ArrayAndATree<T extends Comparable<T>> {
        final T[] contents;
        final BinarySearchTree<T> aTree;

        private ArrayAndATree(T[] contents) {
            this.contents = contents;
            aTree = new BinarySearchTree<>();
        }
    }
    public static void main(String[] args) {

        Integer[] integerItems = {1, 7, 8, 2, -1, -10, 100, 12, 32};
        String[] stringItems = {"jungi", "phil", "bob", "leslie", "tyler", "clarence"};

        ArrayAndATree<Integer> integerArrayAndATree = new ArrayAndATree<>(integerItems);
        ArrayAndATree<String> stringArrayAndATree = new ArrayAndATree<>(stringItems);

        ArrayAndATree<?> taggedArrays[] = {integerArrayAndATree, stringArrayAndATree};
        for (ArrayAndATree<?> a : taggedArrays) {
            putIntoATree(a.aTree, a.contents);
            process(a);
        }
    }

    private static <T extends Comparable<T>> void process(ArrayAndATree<T> a) {
        putIntoATree(a.aTree, a.contents);
    }
}
Victor Sorokin
  • 11,878
  • 2
  • 35
  • 51
0

This is the point of using a common interface to multiple types of objects. Use Comparable.

    for (Comparable[] list : comparableLists) {
        BinarySearchTree<Comparable> tree = ...
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
-1

You don't need to know the concrete type at runtime, generics are applied at compile.

So in your code you can do this:

public static void main(String[] args) {
    Integer[] integerItems = {1, 7, 8, 2, -1, -10, 100, 12, 32};
    String[] stringItems = {"jungi", "phil", "bob", "leslie", "tyler", "clarence"};
    Comparable[][] comparableLists = {integerItems, stringItems};

    for (Comparable[] list : comparableLists) {
        BinarySearchTree b = BinarySearchTree.class.newInstance();
        for (Object element : list) {
            b.add(element); // or whatever method you want to use
        }
    }
}

You just need to be careful to not use the wrong type now as the compiler isn't giving you any guidance

tddmonkey
  • 20,798
  • 10
  • 58
  • 67