1

My project uses an external library which provides classes A and B (where B extends A). I want to add a few methods to A, but I want them to be in B too, so I have created an interface Custom and created the classes:

  • CustomA extends A implements Custom
  • CustomB extends B implements Custom

I now want to uses those 2 new classes interchangeably in class C, as both attributes and method arguments. I have found this question: Declare an attribute that both extends a class and implements an interface, so I have tried the following code:

public class C<T extends A & Custom>{
   private T attr1;
   private T attr2;
   public void createAttrs() {
       attr1 = new CustomA();
       attr2 = new CustomB();
   }
   public void setAttr1(T attr1) {
       this.attr1 = attr1;
   }
   public void setAttr2(T attr2) {
       this.attr2 = attr2;
   }
}

However this code did not compile because of "Incompatible types" in the createAttrs() method. But CustomA and CustomB both extend A (directly or indirectly) and implement Custom, so it matches the pattern of the Type Variable T.

How can I make this code work?

Edit: What I'm really looking for is a way to use CustomA and CustomB interchangeably, in the same fashion I could originally store both an A and a B object in a variable typed A.

2 Answers2

2

Neither a new CustomA() nor a new CustomB() can't be used within the createAttrs since you're describing a template and at this time you don't know what the type T is gonna be.

It can be a CustomA or a CustomB, but it also can be any class that follows the rule T extends A & Custom.

It makes no sense to make a class generic and use a concrete implementation inside it. So I would suggest getting these attributes from method parameters:

class C<T extends A & Custom> {
    private T attr1;
    private T attr2;

    public void createAttrs(T attr1, T attr2) {
        this.attr1 = attr1;
        this.attr2 = attr2;
    }

    public static void main(String[] args) {
        new C<>().createAttrs(new CustomA(), new CustomB());
    }
}
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • He's likely uses generics to work around the fact that Java doesn't have union types yet, where he could just say `A&Custom` in variable type. – M. Prokhorov Oct 13 '17 at 11:20
  • What I forgot to mention is that I had a method `void doStuff(T attr)` that can take either a `CustomA` or a `CustomB` as an argument. And the same thing applies for my attributes, I don't know in advance if it will be a `CustomA` or `CustomB` – Benoît Vernier Oct 13 '17 at 12:07
  • @BenoîtVernier, I missed out the fact that the `B` extends `A` - corrected the answer. What's the idea to make the class generic? Why wouldn't you go with the concrete `CustomA` and `CustomB` fields? – Andrew Tobilko Oct 13 '17 at 17:06
0

What you say in C is that attr1 and attr2 must be of the same type T which extends A, implements Custom and both CustomA and CustomB are assignment-compatible to it.

No such type exists.

lexicore
  • 42,748
  • 17
  • 132
  • 221