2

I need to create generic list that can act as List<ClassA> or List<ClassB> because I have following situation.

if(e instanceof A)
return A;
else
return B

But I want to populate one List Result which can act as either List<ClassA> Result or List<ClassB> Result, am sure we can use generics here but i am not sure how to use it?

Update

All i want to do is that runtime, my List should be populated with proper type, either class A or class B,

if()
{
    //data is present in List<ClassA> classAList = new ArrayList<ClassA>();
    //return classAList
}
else
{
  //return List<ClassB> classBList = new ArrayList<ClassB>();
}

Hope this helps.

14
  • 5
    Are ClassA and ClassB related to each other, as in they share the same interface or parent class? Commented Apr 26, 2012 at 14:42
  • List is already made generic. If you mean that you need a list which contains only ClassA objects or ClassB objects, you can use List<Object> which encompasses both, then use instanceof to determine the type of each. Commented Apr 26, 2012 at 14:43
  • The whole point of generics is to be type-safe – not to have a type which can change. Commented Apr 26, 2012 at 14:43
  • 1
    List<? extends Object> l .. l.add( (object) A ); l.add ( (object) B ); Commented Apr 26, 2012 at 14:44
  • 1
    @Rachel: As people suggested you should have an Interface or a Base class for ClassA and ClassB. Commented Apr 26, 2012 at 14:49

8 Answers 8

2

So if I understand you correctly, you want to be able to construct a list of ClassA or a list of ClassB depending on if a given object is ClassA or ClassB.

public List<? extends Object> getList(Object e) {
    List<? extends Object> list = new ArrayList<? extends Object>();
    if(e instanceof ClassA) {
        List<ClassA> listA = new ArrayList<ClassA>();
        // Populate list somehow
        list = listA;
    } else if (e instanceof ClassB) {
        List<ClassB> listB = new ArrayList<ClassB>();
        // Populate list somehow
        list = listB;
    }
    return list;
}

Unfortunately, the return type must allow for either type (you can alternatively create two methods with different return types, but they must have different names). However, this allows you to use listA and listB as their own types before assigning it to the more generic list.

However this is a violation of the SOLID principal, so an alternative might be:

public abstract class Root<T> {
    public abstract List<T> getList();
}

public class ClassAList extends Root<ClassA> {
    @Override
    public List<ClassA> getList()  {
        List<ClassA> list = new ArrayList<ClassA>();
        // Populate list somehow
        return list;
    }
}

public class ClassBList extends Root<ClassB> {
    @Override
    public List<ClassB> getList()  {
        List<ClassB> list = new ArrayList<ClassB>();
        // Populate list somehow
        return list;
    }
}

Hope that helps!

Sign up to request clarification or add additional context in comments.

3 Comments

Is this an efficient way of doing it /
am kind of hesitant of doing something like List<? extends Object>, not sure why...could it harm me or not?
Well it's not slow if that's what you mean, though checking what type an object is is not best practice as I've updated my answer to demonstrate. List<? extends Object> just means that it is a list of objects which extend "Object" class. It isn't very meaningful it it's Object.
1
class A extends C{ ... body ... }
class B extends C{ ... body ... }

//will work

List<C> list = new ArrayList<C>();
list.add(new A());
list.add(new B());

Or suggestion by Bernard

Summary :

Your option is to either create a parent class and extend parent class from A and B and add the parent type to the list or create an interface and implement that interface from A and B and put the interface type in the list. Either way you'll end up changing your classes A and B and creating new interface or class

2 Comments

i do not have class C from where class A and class B are extending
@Rachel then your option is to either create a parent class and extend parent class from A and B or create an interface and implement that interface from A and B and put the interface type in the list. Either way you'll end up changing your classes A and B
1

You should use a common interface that both of your classes implement. Say your interface is called MyInterface. Both of your classes can implement this interface and your generic list can be of type List<MyInterface>.

The alternative is that both of your classes have a common base class.

Edit:

Added some examples as requested by OP.

Example interface:

public interface MyInterface
{
   String getName();

   void setName(String name);
}

Example interface implementation:

public class ClassA implements MyInterface
{
   private String name;

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }
}

Example generic list usage:

List<MyInterface> list = new ArrayList<MyInterface>();

list.add(new ClassA());

MyInterface item = list.get(0);

item.setName("Bob");

String name = item.getName();

7 Comments

They do not have common class.
@Rachel: Then use an interface that both classes will implement.
Just have one sample interface and then try to extend everything from there.
everything has a common base class Object
@newacct: That is way too broad to use in a generic list. That would mean you could insert objects of any class type in the generic list, which is not what the OP wants.
|
0

If ClassA and ClassB have a common base class (i.e., they both extend the same class), then you can use the base class type in the generic parameter.

2 Comments

No, they do not have base class.
@Rachel Is it possible to redesign ClassA and ClassB so they have a common base? If not, Bernard's answer above might work.
0

Generics are fundamentally for static time checking. In your case, you've got two types of data, so using generics doesn't make any sense unless A & B share a common ancestor class

1 Comment

so then what are my options here?
0

The only way to do this would be for ClassA and ClassB either to have a common parent class or implement a common interface. In either case, the only way to restrict the list to those specific classes would be if no other classes had that common parent or common interface.

Both of these require either that this common parent or common interface already exists or that you have control over ClassA and ClassB. If they don't and you don't, then there's no way to do what you're after.

4 Comments

currently i do not have common class or i do not have common interface
@Rachel: Do you have control over the classes?
Well, I can modify them...actually other developer has developed it
@Rachel: Then the simplest thing would be to create an empty interface and have those two classes implement the interface.
0

This is only really possible if A and B share a common parent (say C). You could then return a List<C>.

It's possible to return a List<Object> but I'd advise against this and consider reworking your design.

2 Comments

what would be your suggestion
@Rachel It depends what the calling code is doing. I would probably make different methods for each possible class of E
0

Something like this perhaps:

public class Test {
  static class A {}
  static class B {}
  private static List<?> getList() {
    List<A> aList = new ArrayList<A>();
    List<B> bList = new ArrayList<B>();
    aList.add(new A());
    if (aList.size() > 0) {
      return aList;
    } else {
      return bList;
    }
  }

  public static void main(String[] args) {
    List<?> cList = getList();
    System.out.println(cList);
  }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.