2

This is a followup to this question. Essentially, I have the following classes:

public class Parent<B> {

    public B b;

    public Parent(B b) {
        this.b = b;
    }
}

public class Child<B> extends Parent<B> {

    public Child(B b) {
        super(b);
    }
}

And I'd like to have another class that references them:

public class Foo<ParentType<B> extends Parent<B>, B> {
//                         ^ syntax error here: > expected
    public ParentType<B> parent;
    public B otherItem;

    public Foo(ParentType<B> parent, B otherItem) {
        this.parent = parent;
        this.otherItem = otherItem;
        B b = parent.b;
    }
}

I think it's clear to a human what I think the above should do, but Java basically considers it a syntactic mess, starting with the first nested <.

I try removing the <B> part in the class template declaration:

public class Foo<ParentType extends Parent, B> {
    public ParentType<B> parent;
//         ^ (5:12)
    public B otherItem;

    public Foo(ParentType<B> parent, B otherItem) {
//                     ^ same error here
        this.parent = parent;
        this.otherItem = otherItem;
        B b = parent.b;
    }
}

but IntelliJ complains

Type 'ParentType' does not have type parameters

and the compiler gives the error:

Error:(5, 12) java: unexpected type
  required: class
  found:    type parameter ParentType

Eventually I can get all the errors to go away if I make the code look like this:

public class Foo<ParentType extends Parent, B> {
    public ParentType parent;
    public B otherItem;

    public Foo(ParentType parent, B otherItem) {
        this.parent = parent;
        this.otherItem = otherItem;
        Object b = parent.b;
    }
}

However, this doesn't allow me to ensure that b is a B, and I want that to be enforced so that I can pass it to a method that accepts a B, for instance.

The answer to my previous question was to add more templating, but I have only been able to get the code to compile by removing some. Is there a trick I'm missing?

I'm aware that I can workaround this problem by casting, but I'd like to have a solution enforced by the compiler if at all possible.

Community
  • 1
  • 1
Jon McClung
  • 1,619
  • 20
  • 28

1 Answers1

3

Add the type parameter only to the parameterized class, then you should achieve what you want to have:

public class Foo<ParentType extends Parent<B>, B> {
    public ParentType parent;
    public B otherItem;

    public Foo(final ParentType parent, final B otherItem) {
        this.parent = parent;
        this.otherItem = otherItem;
        final B b = parent.b;
    }
}

Now ParentType has to be a subtype of Parent<B> and thus b is a B as long as your ParentType does not override it.

Florian Link
  • 638
  • 4
  • 11