Steve M
Steve M

Reputation: 9784

Generics and Parameterized Constructors

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?

Upvotes: 1

Views: 129

Answers (1)

irreputable
irreputable

Reputation: 45433

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)

Upvotes: 2

Related Questions