Reputation: 10061
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
Upvotes: 3
Views: 435
Reputation: 34271
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>();
}
Upvotes: 14
Reputation: 86084
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.
Upvotes: 0
Reputation: 1545
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>();
}
Upvotes: 0
Reputation: 545658
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.
Upvotes: 0
Reputation: 5563
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.
Upvotes: 0
Reputation: 103807
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. ;-)
Upvotes: 8
Reputation: 6580
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:
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.
Upvotes: 0
Reputation: 23265
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.
Upvotes: 5
Reputation: 60957
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.
Upvotes: 3