4

Say I have this code -

public interface ParentInterface1 {
    public List<? extends ChildInterface1> getChildren();
    public void setChildren(List<? extends ChildInterface1> children);
}
public interface ParentInterface2 {
    public List<? extends ChildInterface2> getChildren();
    public void setChildren(List<? extends ChildInterface2> children);
}
public interface ChildInterface1 {
    public String getField();
    public void setField(String field);
}
public interface ChildInterface2 {
    public String getField();
    public void setField(String field);
}
public class LParentImpl implements ParentInterface1, ParentInterface2 {
    private List<ChildImpl> list;
    public List<ChildImpl> getChildren() {
        return list;
    }
    public void setChildren(List<... wants to accept ChildImpl, which 
                                   implements ChildInterface1 & ChildInterface2> children) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
public class ChildImpl implements ChildInterface1, ChildInterface2 {
    private String field;
    public String getField() {
        return field;
    }
    public void setField(String field) {
        this.field = field;
    }
}

Is there a way to make the setChildren() in the ParentImpl class work, without removing the Generic typing completely from the interfaces and implementation?

I'd like to do something like -

public void setChildren(List<? extends ChildInterface1 & ChildInterface2> children) 

This sort of interface/implementation structure is valid for non Generic types, but it seems some aspect of the run-time erasure of Generics might make this impossible? Or am I missing some magic syntax?

Edit: Using the List<? extends ChildInterface1 & ChildInterface2> yields this compile error -

...\ParentImpl.java:20: > expected
    public void setChildren(List<? extends ChildInterface1 & ChildInterface2> children) {
Richard Nichols
  • 1,910
  • 17
  • 19

4 Answers4

11

You can specify a method that takes an object that implements those two interfaces like this:

public <T extends IFirst & ISecond> void doSomething(T obj) {}

However, it won't matter much in your example, since both your child interfaces specify the same methods.

Jorn
  • 20,612
  • 18
  • 79
  • 126
  • Thank you Jorn! I stumbled upon this thread when trying to do exactly what your answer gave me (although it doesn't answer the original questioner). I tried to do this: public static interface Displayable extends Identifiable, Nameable { } public void print(Displayable obj) { System.out.println("[" + obj.getIdentity() + "] " + obj.getName()); } which doesn't work because the object I am passing doesn't implement Displayable, but not Nameable and Identifiable individually. – Hendy Irawan Feb 17 '10 at 02:46
  • You just prevented me from clicking "Post Your Question". Thanks!. – Fritz Jun 20 '12 at 18:26
4

You can do this:

public class MyClass<T extends ChildInterface1 & ChildInterface2> { ... }

Take a look at Java Generics Wildcarding With Multiple Classes

Community
  • 1
  • 1
cletus
  • 616,129
  • 168
  • 910
  • 942
4

Your problem doesn't makes sense.

ParentInterface1.setChildren accepts List<ChildInterface1>. Therefore so much LParentImpl.setChildern, but you are trying to constrain it so that it does not.

You might want to say, parameterise ParentInterface1/2, but I'd suggest avoiding multiple inheritance of interface wherever possible (not just where generics are involved).

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • You are correct. I was trying to work around the fact you can't satisfy both interfaces with - public void setChildren(List) public void setChildren(List) because of erasure - but I think what I'm trying to do here isn't possible given the mechanics of the language. – Richard Nichols Jul 17 '09 at 01:53
  • You can't have both methods overloaded, because of the language spec (overloading is a static issue, so it would be possible despite erasure). The most restrictive parameter type of the method would be something like `List extends ChildInterface1 | ChildInterface2>` (not valid Java) which isn't useful. Not sure if you can declare it as just `List>`. – Tom Hawtin - tackline Jul 17 '09 at 02:03
0

This isn't an answer, but I have to thank Jorn for his answer!

I stumbled upon this thread when trying to do exactly what your answer gave me (although it doesn't answer the original questioner). I tried to do this:

public static interface Displayable
    extends Identifiable, Nameable { }

public void print(Displayable obj) {
    System.out.println("[" + obj.getIdentity() + "] " + obj.getName());
}

which doesn't work because the object I am passing doesn't implement Displayable, but not Nameable and Identifiable individually.

Using Jorn's technique, I do this:

public <T extends Identifiable & Nameable> void print(T obj) {
    System.out.println("[" + obj.getIdentity() + "] " + obj.getName());
}

and it works flawless!

I hope this will be helpful to others that having the similar problem as me (and stumbled to this thread).

Hendy Irawan
  • 20,498
  • 11
  • 103
  • 114