The following code obviously doesn't work because List<E> is abstract:
public class MyList {
private List<E> list;
public MyList() {
this.list = new List<E>();
}
}
How can I initialize MyList class with an empty constructor if I need the list variable to be a LinkedList or a ArrayList depending on my needs?
I'm not sure whether this is what you're asking...
public class MyList {
private List<E> list;
public MyList() {
if (myNeeds)
this.list = new LinkedList<E>();
else
this.list = new ArrayList<E>();
}
}
There are better alternatives for what you are trying to achieve:
Create a base class (abstract?) and override it twice, once for ArrayList and one for LinkedList
Inject the appropriate list to your class (dependency injection)
Why not use a protected (and possibly abstract method) like:
public abstract class MyList<T> {
protected final List<T> list;
public MyList() {
list = createList();
}
public MyList(boolean preferLinked) {
list = preferLinked? new LinkedList<T>() : new ArrayList<T>();
}
// Allows client code which subclasses from MyList to override the
// default behaviour
protected List<T> createList() {
return new ArrayList<T>();
}
}
boolean shouldThisBeAnArrayList=true; // Set to false to use LinkedList
if(shouldThisBeAnArrayList) {
this.list = new ArrayList<E>();
}
else {
this.list=new LinkedList<E>();
}
You need to determine what "your needs" are in the default case - LinkedList or ArrayList. If you can't - say, if the need changes depending on something that happens over the object's lifetime, then the list needs to change, too.
List is an interface and as such, cannot be constructed. Only implementations of said interface can be constructed (e.g. ArrayList). Also, you need to know the type (E) at construction.
This should work:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class MyList<E> {
private List<E> list;
public MyList(boolean linked) {
if (linked) {
list = new LinkedList<E>();
} else {
list = new ArrayList<E>();
}
}
}
I would think you could do the following:
public class MyList<T> {
private List<T> list;
public MyList() {
this.list = new ArrayList<T>();
}
}
As I understand, you cannot use just a empty constructor, because you have a decision node in your model, when you need to choose between the type of the list, so, you will have to tell the program any way what kind of list will be.
This seems to be the best solution in my opinion:
public class MyList {
private List<E> list;
public MyList() {
this.list = new LinkedList<E>();
}
//an overload for another type,
public MyList(bool INeedArray) {
if (INeedArray)
this.list = new ArrayList<E>();
}
}
public class MyList<T> {
private List<T> list = new ArrayList<T>();
}
This is what I use in classes.. I have for a long initialized what I could when defining the private variable it self.
Related
I have a problem with Java's Generic System.
In my program is a wrapper for lists, that should have a method to return it's inner list:
public class Wrapper<T, S extends List<T>> {
private S list;
public Wrapper(S list) {
this.list = list;
}
public S get() {
return list;
}
}
Then there is a Context that holds a Map with different Wrappers and a method that returns the list of the wrapper associated with the id:
public class Context {
private Map<String, Wrapper> map;
public Wrappers() {
map.put("a", new Wrapper(ArrayList<String>());
map.put("b", new Wrapper(LinkedList<Integer>());
}
public <T, S extends List<T>> S getList(String id) {
return map.get(id).get();
}
}
Now when I call getList() I want to have a compiler warning or at least a way to realise an error before a ClassCastException gets thrown.
public class Receiver {
public doSomething() {
Context c = new Context();
c.createWrappers();
// Ok
ArrayList<String> list1 = c.getList("a");
LinkedList<Integer> list2 = c.getList("b");
// Compiler error or some way do check in getList().
ArrayList<Integer> list3 = c.getList("a");
LinkedList<String> list4 = c.getList("b");
}
}
I've actually tried a lot of things like changing the Wrapper definition to:
public class Wrapper<T, S extends List>
But when I want to implement the get() function I run into a problem I can either define the function like this:
public List<T> get() {
return list;
}
or like this
public S get() {
return list;
}
In the first example it would still be possible to do this.
public doSomething() {
//...
LinkedList<String> list = c.getList("a");
}
and in the second example it would be possible to do this.
public doSomething() {
//...
ArrayList<Integer> list = c.getList("a");
}
Is there any way to define the get method in a way like this?
public S<T> get() {
return list;
}
It seems to me like there is no way to check both the type of the list and the type of the elements at the same time.
The compiler has no way of knowing what return type is associated with the particular string you passed (strings cannot be made type-safe).
However, you could replace strings with type-safe marker objects:
class ListId<T> {
public ListId(string name) { ... }
public static final ListId<ArrayList<String>> A = new ListId<>("a");
public static final ListId<LinkedList<Integer>> B = new ListId<>("b");
}
public T getList<T>(ListId<T> id)
This is my current code:
import java.util.ArrayList;
public class SingletonAList<T> {
private final ArrayList<T> aL = new ArrayList<T>();
SingletonAList() {}
public ArrayList<T> getList(T t) {
return aL;
}
}
What I am looking to do is have it return a Singleton List of the type if it exists; if not to create a new one of type T;
so example three getList calls are made;
getList(Obj1);
getList(Obj2);
getList(Obj1);
On first getList a new ArrayList<Obj1> would be created;
on second getList a new ArrayList<Obj2> would be created;
and on third getList the same arrayList from the first call would be returned.
Any implementation suggestions? I have been messing around...it seems that the new call must be in the getList call; and possibly another list of Types that have already been instantiated?
One solution could be something like :
public class SingletonAList {
private static Map<Class, List> lists = new HashMap<Class, List>();
public static <T> List<T> getInstance(Class<T> klass) {
if (!lists.containsKey(klass)) {
lists.put(klass, new ArrayList<T>());
}
return lists.get(klass);
}
}
After, you can call it with SingletonAList.getInstance(String.class);
I wanna set a List in a class using a wildcard as type:
public List<?> setList(List<?> list){
this.list = list;
}
But I only will accept some types of the List elements. The example contains only the String approach but I will accept String, Double or Integer f.e..
I know this approach:
public void setList(List<?> list){
if(!list.isEmpty())
if(list.get(0).getClass().equals(String.class))
this.list = list;
else
throw new IllegalArgumentException();
else
// what to do?
}
If the List isn't empty I can check the first elements class. If it's of the String.class I will set the List, otherwise an Exception will be thrown.
But how should I react if the List is empty? Because AFAIK I can't check the type of the wildcard because of type erasure. So, I can't instanciate a empty List.
Should I just do this.list = null;? Or should I only accept not empty Lists and throw an Exception if it's empty? I appreciate any suggestion. Because this code will be reused and the guy who works with it should be informed about what happens.
To answer directly to your question: there will be no problem with an empty list.
Because of type erasure there is no difference between List<String>, List<Double> or simple List at runtime.
You can even fool the compiler and do things like
List<String> stringList = new ArrayList<String>();
stringList.add("foo");
List rawList = stringList;
rawList.add(42);
List<Integer> integerList = rawList;
having three references to the same list with different treatment only by the compiler. (You will get some warnings dependend on your compiler settings, but that's all.)
If you want to check the consistency at runtime, you have to check every single member of the list
public <T> void setList(List<T> list, Class<T> clazz) {
for (T t : list) {
if(!clazz.equals(t.getClass())) {
throw new YourPreferedKindOfException();
}
}
this.list = list;
}
(check for null arguments omitted)
Suitable exception could be IllegalArgumentException, called e.g.
setList(stringList, String.class);
To be realy sure at runtime you have to copy the list, because your function got the list as reference and the content of it can be modified outside your function later.
I have three approaches here:
SIMPLE GENERIC APPROACH
You have to parametrize the class holding the list. By creating a new instance with a specified generic type. That would be a type-safe approach.
public class ListHolder<T> {
private List<T> list;
public void setList(List<T> list) {
this.list = list;
}
public static void main(String[] args) {
ListHolder<String> sl = new ListHolder<String>();
sl.setList(new ArrayList<String>());
ListHolder<Double> dl = new ListHolder<Double>();
dl.setList(new ArrayList<Double>());
}
}
DYNAMIC PERMISSION BASED APPROACH
Here we populate a set with classes that are allowed.
public class ListHolder {
private Set<Class<?>> allowed = new HashSet<Class<?>>();
private List<?> list;
public <T> void setList(List<T> list) {
if (list.isEmpty()) {
// problem is we can't check type here. Exception would be better
list = Collections.<T> emptyList();
} else {
Class<?> clazz = list.get(0).getClass();
if (allowed.contains(clazz)) {
this.list = list;
} else {
throw new IllegalArgumentException("Type "
+ clazz.getSimpleName() + " not allowed!");
}
}
}
public void allowClass(Class<?> clazz) {
allowed.add(clazz);
}
}
STATIC PERSMISSION BASED APPROACH
Here the checking takes place at compile time.
public class ListHolder {
private List<?> list;
public static final Allowed<String> STRING = new Allowed<String>();
public static final Allowed<Double> DOUBLE = new Allowed<Double>();
public <T> void setList(List<T> list, Allowed<T> permission) {
if (permission == null)
throw new NullPointerException("Permission is null!");
this.list = list;
if (list == null) // if you don't want list to be null
this.list = Collections.<T>emptyList(); // added type parameter to make it clearer for reader
// ...compiler does that implicitly
}
private static class Allowed<T> {
}
public static void main(String[] args) {
ListHolder l = new ListHolder();
List<String> strings = new ArrayList<String>();
List<Double> doubles = new ArrayList<Double>();
List<Integer> integers = new ArrayList<Integer>();
l.setList(strings, ListHolder.STRING);
l.setList(doubles, ListHolder.DOUBLE);
//l.setList(integers, ListHolder.DOUBLE); Does not even compile
}
}
I have a method like this
public static LinkedList<Object> getListObjectWithConditionInXMLFile(String className){
LinkedList<Object> lstObj = new LinkedList<Object>();
if(className.equals("Customer")){
//read Data from XML File
Customer customer = ...;
lstObj.add(customer);
}
....
return lstObj;
}
after that i call this method and want to cast :
LinkedList<Customer> lstCustomer = (LinkedList<Customer>()) getListObjectWithConditionInXMLFile("Customer");
But it cannot cast.
How can i cast from LinkedList to LinkedList ?
Pls help me ! thanks so much !
You can refactor your method to something like this:
public static <E> LinkedList<E> getListObjectWithConditionInXMLFile(Class<E> type){
LinkedList<E> lstObj = new LinkedList<E>();
if (type.equals(Customer.class)) {
Customer customer = ...
lstObj.add((E)customer);
}
return lstObj;
}
By making the method generic and passing a Class parameter you can return a list of the right type.
You can call it this way
List<Customer> l = getListObjectWithConditionInXMLFile(Customer.class);
You will have to create new List and add casted object to the new linked list of Customer.
LinkedList<Customer> custList = new LinkedList<>();
for(Object obj: getListObjectWithConditionInXMLFile("Customer")) {
custList.add((Customer)obj));
}
Or, it is better to use generics if possible as mentioned by "Boris the Spider" in comment.
public static <T> LinkedList<T> getListObjectWithConditionInXMLFile(Class<T> requiredClass)
The definition can be as follows as given by "micha".
public static <T> LinkedList<T> getListObjectWithConditionInXMLFile(Class<T> requiredClass){
LinkedList<T> listObj = new LinkedList<>();
if (requiredClass.equals(Customer.class)) {
Customer customer = /*...*/
listObj.add((T)customer);
}
return listObj;
}
Then, You can call as
LinkedList<Customer> custList = getListObjectWithConditionInXMLFile(Customer.class);
I want to do something like this
private <T extends List<?>> List<?> getFirstFiveElements(T list) {
//body
}
However when I tray to pass in the arguments it is not working
List<A> a = new LinkedList<A>;
List<B> b = new LinkedList<B>;
getFirstFiveElements(a);
getFirstFiveElements(b);
so any suggestion how I cam make this work.
The following should work just fine.
private static <A, T extends List<A>> List<A> getFirstFiveElements(T list) {
//
}
T serves no useful purpose here, and therefore can be eliminated.
private static <A> List<A> getFirstFiveElements(List<A> list) {
//
}
If you want the method to return the same type that it takes (i.e. ArrayList for ArrayList, LinkedList for LinkedList), then sorry to tell you, Java's type system is not capable of that.
Great 2 second later, I have found the magic combination. Anyway for all of the others who stumble upon this here is what worked for me
private <T> List<T> getStart(List<T> list)
This works for me:
import java.util.*;
public class Test {
private static <T extends List<?>> List<?> getFirstFiveElements(T list) {
List<Object> result = new LinkedList<Object>();
for (int i = 0; i < 5 && i < list.size(); i++) {
result.add(list.get(i));
}
return result;
}
public static void main(String[] args) {
List<Integer> a = new LinkedList<Integer>();
a.add(1);
a.add(2);
a.add(3);
a.add(4);
a.add(5);
a.add(6);
a.add(7);
System.out.println(getFirstFiveElements(a));
}
}
Why do you want to use template? Would not be enough to use this:
private List<?> getFirstFiveElements(List<?> list) {
//body
}