1

I would like to know how to write a class in Java that has a nested template parameter. This question describes nested, template parameters, but assumes that wildcards will be used. I would like to name all the types involved, so I don't want to use wildcards. Note that I understand that the wildcards are used for covariance. I am perfectly fine with my templated type being invariant as long as I know the types it's made out of. Below is an example of code that compiles, but doesn't give me all the information I want.

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);
    }
}

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;
    }
}


public class Main {
    public static void main(String[] args) {
        Parent<String> stringParent = new Parent<>("hello");
        Child<Integer> intChild = new Child<>(5);

        Foo<Parent, String> foo = new Foo<>(stringParent, "bonjour");
        Foo<Child, Integer> childFoo = new Foo<>(intChild, 42);

        Object b = foo.parent.b;
        System.out.println(b + ", " + b.getClass());
    }
}

I am forced to declare the type of foo.parent.b as an Object, even though I know it is a String (and the program knows it too: the output is hello, class java.lang.String). I would like to write the code more like this:

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;
    }
}

or something along those lines, explicitly forcing parent's type to be linked to 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

The locations where the error occurs are marked above.

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

1 Answers1

2

This is because you didn't specify the type parameter of Parent here:

Foo<Parent, String> foo = new Foo<>(stringParent, "bonjour");
Foo<Child, Integer> childFoo = new Foo<>(intChildBar, 42);

Object b = foo.parent.b;

Instead of Foo<Parent, String>, if you specify the type parameter of Parent, that is Foo<Parent<String>, String>, then you can get the correct type of b:

Foo<Parent<String>, String> foo = new Foo<>(stringParent, "bonjour");
Foo<Child, Integer> childFoo = new Foo<>(intChildBar, 42);

String b = foo.parent.b;
janos
  • 120,954
  • 29
  • 226
  • 236
  • @JonMcClung if you read janos answer, it pretty much tells you the next answer, you know how he mentions to change the Parent to Parent... are things clicking? – Derrops Dec 19 '16 at 06:29
  • @Snickers3192 sorry, things aren't exactly clicking. I've tried just adding `` to various parts of the class, but that only results in errors. My follow-up question is here if you'd like to provide more insight: http://stackoverflow.com/q/41217172/4714742 – Jon McClung Dec 19 '16 at 06:52
  • You need to add type parameters to Parent at the start of your Foo declaration. By the way your child class is redundant. You should think really carefully about how to use inheritance in your design of a class hierarchy. Helpful tip: if you don't add any methods to an inherited class, you probably don't need inheritance. – Derrops Dec 19 '16 at 23:05