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.

1 Answer 1

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.

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

1 Comment

That makes a lot of sense in hindsight. I really appreciate it!

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.