1

This is an extension of this previous question about parameterized methods. I am reading the same book. After the example in the previous question, the author improves the

BinaryTree<T extends Comparable<? super T>>

class yet again (and he really does this time around) by adding the following constructor

public  <E extends T> BinaryTree(E[] items) {
    for(E item : items) {
        add(item);
}

In the spirit of the previous question I tried this constructor instead:

public BinaryTree(T[] items) {
    for(T item : items) {
        add(item);
    }
}

and the example code does not compile with my constructor:

public static void main(String[] args) {
    Manager[] managers = { new Manager("Jane", 1), new Manager("Joe", 3), new Manager("Freda", 3), new Manager("Bert", 2), new Manager("Ann", 2), new Manager("Dave", 2) };
    BinaryTree<Person> people = new BinaryTree<>(managers);
}

What is this difference between changing the add() method in the previous question and changing this constructor? Why can't I pass a subtype of T in my constructor?

1 Answer 1

2

For the 2nd constructor, when compiler sees

new BinaryTree<>(managers)

it needs to infer T for the <>. In this case, inference is based on managers: T[]=Manager[] => T=Manager.

Therefore the expression yields a BinaryTree<Manager>, which cannot be assigned to BinaryTree<Person>.

Two workarounds:

new BinaryTree<Person>(managers);

new BinaryTree((Person[])managers);

For the 1st constructor

<E extends T> BinaryTree(E[] items)

we have two things to infer now, E and T, in expression new BinaryTree<>(managers)

Now E=Manager is inferred; however T is not inferred yet. The compiler then looks at the target type Binary<Person>, which helps to infer that T=Person.


Java type inference is quite messy. Why would any programmer care to learn what I have just described? The lesson is, when in doubt, supply type arguments explicitly.

Between the two constructors, I would definitely choose BinaryTree(T[] items). The E version is just more complexity without benefits (though it happens to work better for this particular example)

Sign up to request clarification or add additional context in comments.

2 Comments

This all makes sense, thanks. So I guess there is not much of point in using <E extends T> BinaryTree(E[] items)
There's no point, since the T[] arg would accept any X[] where X is subtype of T. Note this won't work for List. If we want to accept any List<X> where X is subtype of T, we need List<? extends T> as the arg type.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.