16

I'm trying to develop a general table loader which schema is known at runtime. This requires having a class which contains a list of different types of elements and supports various get and set method such as getInt(int index), asString(int index), asStringList(int index). The types of elements I consider are Integer, Double, String, and List<Integer>, List<Double> and List<String>. The actual type of each element is known in run time, and I will store them in a List describing its schema for further processing.

My question is: should I store such list of elements in List<Object> or List<? extends Object>? or is there better way to implement such class?

Joe F
  • 4,174
  • 1
  • 14
  • 13
keelar
  • 5,814
  • 7
  • 40
  • 79
  • At runtime, `List` becomes `List`, so no chance here, you'd have to have two separate sets of classes – fge Jun 14 '13 at 21:36
  • 1
    That's a really nasty code smell you got there. – Brian Roach Jun 14 '13 at 21:38
  • @Brain Roach: I have included the reason why I need this. – keelar Jun 14 '13 at 21:40
  • 1
    @Brain Roach: I know doing things wrong could be nasty, so that's why I ask. Can you provide a cleaner way to do this? – keelar Jun 14 '13 at 21:47
  • I think dasblinkenlight has a quite clean solution that avoids the whole list type problem. Basically he is using a good OOP principle: prefer composition over inheritance. – oligofren Jun 14 '13 at 21:57

2 Answers2

20

Since the common ancestor of your classes is Object, and because List<? extends Object> does not make things any cleaner (after all, everything extends Object) it looks like List<Object> would be an OK choice.

However, such list would be a mixed bag: you would need to check run-time type of the object inside, and make decisions based on that. This is definitely not a good thing.

A better alternative would be creating your own class that implements operations on elements of the list the uniform way, and make one subclass for each subtype that implements these operations differently. This would let you treat the list in a uniform way, pushing the per-object differentiation into your wrappers.

public interface ItemWrapper {
    int calculateSomething();
}

public abstract class IntWrapper implements ItemWrapper {
    private int value;

    public IntWrapper(int v) {
      value=v; 
    }

    public int calculateSomething() {
      return value;
    }
}

public abstract class DoubleListWrapper implements ItemWrapper {
    private List<Double> list;

    public DoubleListWrapper (List<Double> lst) {
      list = lst; 
    }

    public int calculateSomething() {
        int res;
        for (Double d : list) {
            res += d;
        }

        return res;
    }
}
// ...and so on

Now you can make a list of ItemWrapper objects, and calculateSomething on them without checking their type:

List<ItemWrapper> myList = new ArrayList<ItemWrapper>();

for (ItemWrapper w : myList) {
    System.out.println(
      w.calculateSomething());
}
Alex Walczak
  • 1,276
  • 1
  • 12
  • 27
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Why do I get "Abstract methods cannot have a body" on "public abstract int"? – Zon Dec 20 '15 at 17:08
  • @Zon Because it was my copy/paste error :-) Thanks for pointing it out. – Sergey Kalinichenko Dec 20 '15 at 22:16
  • myList is always empty and print is unaccessible. How can we add any ItemWrapper to myList before looping, if there is no ItemWrapper class (only interface)? – Zon Jan 03 '16 at 19:45
  • @Zon I am not sure I understand your question. The best way to ask a follow-up question is to ask it as a new question, rather than commenting, because this way you would get full access to code mark-up, letting you provide a better example of what you are trying to ask. – Sergey Kalinichenko Jan 03 '16 at 20:01
  • @dasblinkenlight Could you please expand on the part about disadvantages using List, the one where you say: 'you would need to check run-time type of the object inside, and make decisions based on that'? What may be the cases when such run-time checks are necessary? – TomateFraiche Jul 15 '19 at 08:40
  • 1
    @TomateFraiche At some point you would need to iterate the list, and do something to some or all its elements. Unless all operations on list elements conform to what Object supports, you would have to write code that processes, say, integers differently from strings, so the code would look like `if (w instanceof Integer) ... else if (w instanceof String)...` and so on. – Sergey Kalinichenko Jul 15 '19 at 09:46
9

You should use List<Object>, or whatever super class is the closest fit. I once asked a similar question that amassed a few very good answers that has a lot of relevant information for you. I would check it out. Basically it all comes down to PECS - Producer Extends, Consumer Super.

Community
  • 1
  • 1
oligofren
  • 20,744
  • 16
  • 93
  • 180
  • Thank you for the pointer, I tried but didn't found this post. Thank you for providing this information. – keelar Jun 14 '13 at 21:42