views:

522

answers:

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) {
+2  A: 

You can do this:

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

Take a look at Java Generics Wildcarding With Multiple Classes

cletus
That is not valid syntax.
newacct
It's almost valid. See my answer.
Jorn
+5  A: 

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
You are correct. I was trying to work around the fact you can't satisfy both interfaces with - public void setChildren(List<ChildInteface1>)public void setChildren(List<ChildInteface2>)because of erasure - but I think what I'm trying to do here isn't possible given the mechanics of the language.
Richard Nichols
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
+3  A: 

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
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
A: 

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