tags:

views:

233

answers:

9

hello

In order to be able to substitute a specific implementation, it is commonly known to write

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

instead of

ArrayList<AnyType> myList = new ArrayList<AnyType>();

This is easy to understand, this way you might change the implementation from ArrayList to LinkedList or any other kind of List with ease.

Well... this is all good and nice, but as I cannot instanciate "List" directly, I therefore would be required to type

public List<AnyType> getSpecificList()
{
    return new ArrayList<AnyType>();
}

which makes the previous pattern quite senseless. What if I now want to replace the implementation by an LinkedList instead of an ArrayList? It would be required to change it on two positions.

Is it possible to have something like this (I know the syntax is absolutely incorrect)?

public class MyClass<T>
{
    Type myListImplementation = ArrayList;

    List<T> myList = new myListImplementation<T>();

    public List<T> getSpecificList()
    {
        return new myListImplementation<T>();
    }
}

This would allow me to simply change the word "ArrayList" to "LinkedList" and everything is fine. I know that both lists may have different constructors and this would not work "as is". And I don't really want to add a second type-parameter for specifying the list-implementation that is being used.

Is there any clean mechanism to fix this?^

Thanks in advance and best regards Atmocreations

+2  A: 

This really has nothing to do with generics, but is instead having to do with polymorphism.

The point of using List (or List<T>) instead of ArrayList (or ArrayList<T>) is that List is an interface while ArrayList is a concrete implementation. Interfaces are good, and you should use them, but they really have nothing to do with generics directly.

In your example, why do you need to make the actual type of your List a variable? If you really want to abstract away the creation of the object, you should use a factory method, as it appears you're doing.

Generally speaking, the purpose of polymorphism in general and interfaces in specific is that clients ("consumers") of your data objects don't need to know implementation details. However, the code that creates ("produces") your objects should be in a position to know implementation details (since it's populating the object). So it shouldn't be problematic to have the object creation code know that it's creating an ArrayList or a LinkedList or whatever.

Daniel Pryden
To be clear, List<T> is an abstract class; IList<T> is the interface.
Ryan Emerle
@Ryan, to be clear, the question is about Java, where List<T> is actually an interface and IList<T> does not exist in std library ;)
Juha Syrjälä
@Juha: You are correct. @Ryan: Your statement would be correct if we were talking about C#, but it is incorrect, because we are talking about Java.
Daniel Pryden
+5  A: 

What if I now want to replace the implementation by an LinkedList instead of an ArrayList? It would be required to change it on two positions.

No, you wouldn't. You could change each location independently. i.e., one of those allocations could be a LinkedList and the other could be an ArrayList.

Keith Randall
I understood his complaint to be that he **wants** to only change it in one place and have both actual lists now be the new class.
Andrzej Doyle
It's good to point that out, thanks. But unfortunately this doesn't really answer my question. It in fact *could* be a different implementation. But I want it to be the same. And that I don't need to change each location independently, I would like to have something like a type-alias that is replaced. If Java had C's #define, everything was fine.
Atmocreations
@dtsazza: +1 for entirely having understood the problem
Atmocreations
+6  A: 

Erm - as far as I understand your question, what you want to do is already possible (and nothing to do with generics).

You will always need to give the exact type of the list (or any class) when actually making a constructor call, that's unavoidable. Likewise, you can always avoid specifics everywhere else (storing it in a variable, returning it from a method, passing it as a method parameter, etc.). In your case you're already doing this - by declaring myList as simply a List, you don't need to change it's declared type if you change the concrete class of list you store in it.

I think your question may be around the fact that you're creating two different lists in the same class (but both of the same type), and you want to abstract this out. You can do this quite easily with a factory-type pattern; either with a separate factory, or in your case, just replacing the myList declaration with

List<T> myList = getSpecificList();

Edit - out of interest, the closest thing you could get to your original proposed fix would be using reflection:

public class MyClass<T>
{
    Class<? extends List<T>> myListClass = ArrayList.class;

    List<T> myList = myListClass.newInstance();

    public List<T> getSpecificList()
    {
        return myListClass.newInstance();
    }
}

But don't do this - it's slow, inflexible, unusual (so harder to grok for other developers) and completely unnecessary in this case...

Double-edit: oh, and you'd have to deal with a whole bunch of reflection-based checked exceptions that I've left as an exercise to the reader, just in case you felt tempted. ;-)

Andrzej Doyle
thanks, the reflection-thing looks good but I won't use it as you said I shouldn't. +1 for the good response.
Atmocreations
Yes, it can be useful in some situations (where you want your class to be externally configurable, and the lower performance and higher complexity are acceptable tradeoffs). For general purpose programming, though, there's no reason to use it over more conventional constructs like the factory pattern.
Andrzej Doyle
+11  A: 

Why not use some kind of factory pattern instead of instantiating a specific list implementation directly. Then you need to change list implementation only in one place, inside the factory method.

For example you start with:

 List<T> createList() {
     return new ArrayList<T>();
 } 

 List<T> myList1 = createList();
 List<T> myList2 = createList();

Later, if you decide that you need a linked list instead, you just change the implementation of createList() and the rest of your code stays the same.

List<T> createList() {
    return new LinkedList<T>();
}
Juha Syrjälä
+1 for communicating this much clearer than my rambling answer. :-)
Andrzej Doyle
thank you for the really simple, clear and instantly-usable response. Will do it that way!
Atmocreations
A: 

The only way to instantiate a "parameterized" List implementation would be through reflection, but you're definitely making the right first step, by returning the List interface rather than a complex class. Some ideas that could work:

  1. write a private method like newList() which just returns an empty List implementation. Use this throughout your class and then if you want to change it from ArrayList to LinkedList, you only have to change the implementation of that newList() method. This is similar to your getSpecificList() method
  2. If you want clients to choose the List implementation: accept a List class in the constructor:

    public MyClass(Class<? extends List<T>>) { ... }

Idea #2 would require reflection to instantiate the List implementation, however, which probably isn't what you want.

Brad Cupit
A: 

If the "Array" or "Linked" part of the list is important to your implementation, then expose it. If it isn't important, then don't.

You could have an interface like:

 ArrayList<T> createArrayList();

if for some reason the implementation of List were important. Returning "List" is good practice when all you need is the List-ishness, in which case implementation is less important.

Alex Feinman
A: 

They way I understand your question (I could be mistaken though; your question isn’t very clear), you are simply searching the correct syntax for a generic method – which simply looks like this:

public <T> List<T> getSpecificList()
{
    return new ArrayList<T>();
}

– Notice the leading <T>. Now if you want to change the type of the list, this change is restricted to one single position.

Konrad Rudolph
good idea. But I don't want to change the type of the list-elements (which would be T) but the list implementation itself.
Atmocreations
A: 

If you don't initialize myList, then you only need to change things in one spot. Unless of course you need to use any of the methods unique to ArrayList...

List<AnyType> myList = getSpecicList();

public List<AnyType> getSpecificList()
{
    return new ArrayList<AnyType>();
}
CJS
A: 

How about this?

public class MyClass<T>
{
    List<T> myList = this.getSpecificList();

    public List<T> getSpecificList()
    {
        return new ArrayList<T>();
    }
}

Now you only have to change the type in one place.

recursive