2

I have a situation in which I have to create a generic method that can accept List of child objects but not the parent class objects.

Say I have

class ClassA {}

which is getting extended by

class ClassB extends ClassA {}
class ClassC extends ClassA {}
executeMethod(List</* either ClassB or ClassC but not ClassA */>)

Can we achieve it using generics?

Radiodef
  • 37,180
  • 14
  • 90
  • 125

3 Answers3

4

I'm not sure why you can't just allow List<? extends ClassA> but you could try:

<T Extends ClassA> void executeMethod(List<? extends T>);
//not sure if this will work but worth a try.

Or

public interface ClassX {}
public class ClassA {

    void executeMethod(List<? extends ClassX);
}
public ClassB extends ClassA implements ClassX {}
public ClassC extends ClassA implements ClassX {}
redge
  • 1,182
  • 7
  • 6
  • First solution does not restrict enough: you can pass a List. I like the second solution with an interface, that can be a _marker_. It's more flexible than creating a new intermediate class in the hierarchy as proposed by @beresfordt – T.Gounelle Mar 28 '15 at 14:24
  • hey redge .. can you plz share some code example on the same. Interface approach is gving me compilation errors: List implements InterfaceA> as implements is not allowed in generics. if I am using List extends ClassA> them I am able to assign list of ClassA, ClassB and ClassC all. I want to stop the acceptance of List . – Himanshu Singh Mar 29 '15 at 18:42
  • The generic specifier is always `T extends S` regardless of whether S is a class or interface. There is no implements keyword in generics. So your code should read `List extends InterfaceA> ` – redge Mar 29 '15 at 20:51
  • Thanks redge for sharing your views .. I tried another way also List super ClassA> .. but that was also accepting List as acceptable which I didn't want. what is the use of super ClassA> – Himanshu Singh Mar 30 '15 at 01:39
  • This specifies that the parameter must be an instance of a superclass of ClassA. ie super ClassB> would be satisfied by ClassB and ClassA but not ClasaC – redge Mar 30 '15 at 05:32
2

Making A abstract is the easiest way to do it. If you cannot make A abstract you could create an abstract class which extends A, and then is itself extended by B and C, eg:

class A {

}

abstract class X extends A {

}

class B extends X {

}

class C extends X {

}

public void executeMethod(List<? extends X> list) {

}
beresfordt
  • 5,088
  • 10
  • 35
  • 43
  • 1
    Shouldn't it be `List extends X>` as B and C should be allowed and A not? – MinecraftShamrock Mar 28 '15 at 12:44
  • Not to my understanding; there is a discussion of when to use super/extends here - [Producer Extends Consumer Super](http://stackoverflow.com/q/2723397/658663) – beresfordt Mar 28 '15 at 12:47
  • 1
    The condition was: `B or C but not A`, which would be fulfilled by `extends` because `B extends X`, `C extends X` and `A not extends X`. But with `super` it's exactly the opposit thing: `B not super X`, `C not super X` but `A super X` which does not fulfill the condition. – MinecraftShamrock Mar 28 '15 at 12:50
  • Yeah, you're right - generics are not my strong point. Thanks for the correction, will update my answer – beresfordt Mar 28 '15 at 12:56
0

This is cannot be done as Pshemo said there is no or or not operation for this. You could however to something like this:

public static void executeMethod(List<ClassB> list){ 
    sharedMethodPerhaps( ... );
}

public static void executeMethod(ArrayList<ClassC> list){
    sharedMethodPerhaps( ... );
}

private static void sharedMethodPerhaps( ... ){ 
    ...
}

This way you have two method with the same name and one only accepts a list with ClassB objects and the other only accepts a list with ClassC objects. And because List and ArrayList are different so enough the two methods do not collide. And the sharedMethodPerhaps is private so you control what code class it and how.

I hope this help :)

Roan
  • 1,200
  • 2
  • 19
  • 32