Petr
Petr

Reputation: 118

Java generic class constructor invocation

I have following code:

public class A {}

public class B extends A {}

public class C <T extends A> {

  private final T data;

  public C(final T data) {
    this.data = data;
  }
}

public class D<T extends B> extends C<T> {

  public D(T data) {
    super(data);
  }

  public D() {
    this(new B());
  }

  public static D<B> create() {
    return new D(new B());
  }
}

There is a compile error in the class D:

error: no suitable constructor found for D(B)
    this(new B());
constructor D.D() is not applicable
  (actual and formal argument lists differ in length)
constructor D.D(T) is not applicable
  (actual argument B cannot be converted to T by method invocation conversion)
where T is a type-variable:
T extends B declared in class D

What is confusing me is the fact, that the static method D.create() that does basically the same is compiled without any errors. Can anyone explain this error? And the difference between D() and D.create()?

Upvotes: 3

Views: 155

Answers (2)

Ren&#233; Link
Ren&#233; Link

Reputation: 51343

Because generic type T of class D is not bound

This will work

public class E extends D<B> {

    public E() {
        super(new B()); // call to D's constructor public D(T data)
    }
}

normally you would call the constructor of D in this way:

new D<B>(new B());

but you CAN NOT do this

public D() {
    this<B>(new B());
}

Another example.

Change the code a little bit and you will see the problem.

class BBB extends B {
}

class C<T extends A> {

    protected final T data;

    public C(final T data) {
        this.data = data;
    }
}

class D<T extends B> extends C<T> {

    public D() {
        this(new B());
    }

    public T getData(){
        return data;
    }
}

D<BBB> dOfBBB = new D<BBB>();
BBB data = dOfBBB.getData(); // So if this(new B()) would work 
                              // how can the data then be returned?
                              // Because BBB is returned but it would be 
                              // initialized with only a B instance

Upvotes: 1

Bohemian
Bohemian

Reputation: 424983

The error is there because for class D it is not known that the type will be B, only that the generic type will extend B - you have assumed it's going to be B because there are no other classes (yet) in your class hierarchy (a fact that the compiler must consider may change in the future).


Note that in the factory method you are instantiating the raw type for D (one without a generic parameter). Instead, provide a type:

You should change:

public static D<B> create() {
    return new D(new B());
}

to:

public static D<B> create() {
    return new D<B>(new B()); // Note: Added generic parameter <B>
}

Upvotes: 4

Related Questions