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);
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)
I would like a method to return a different type of List.
I tried something like the following but not sure if this approach is correct or not. How can I do this?
public <T> List<T> getPageDetails(Long adId,String source);
Based on the source I will return a different List of objects in the implementation method.
Like in implementation if the source is 1, then will have to return List of objects type1, if the source is 2 then list of objects type2, etc.
private Object objT;
public <T> List<T> magicalListGetter(Class<T> cls) {
List<T> list = new ArrayList<>();
list.add(cls.cast(actuallyT));
try {
list.add(cls.getConstructor().newInstance()); // If default constructor
} ...
return list;
}
One can give a generic type parameter to a method too. You have correctly deduced that one needs the correct class instance, to create things (cls.getConstructor().newInstance()).
Without class :
public <T> List<T> magicalListGetter() {
return new ArrayList<T>();
}
You can use genrics to return multiple list
public <T> List<T> getPageDetails(Long adId,String source);
public static void main(String[] args) {
Solution sol = new Solution();
List<String> list = sol.getPageDetails(String.class, 0l, "source");
}
public <T> List<T> getPageDetails(Class<T> c, Long adId, String source) {
List<T> list = new ArrayList<>();
List<Object> objectList = getObjectList(adId, source);
for (Object o : objectList) {
T t = c.cast(o);
list.add(t);
}
return list;
}
private List<Object> getObjectList(Long adId, String source) {
// TODO Auto-generated method stub
return null;
}
If I have the following code:
public class DummyClass<T> {
public List<T> getList() {
return new ArrayList<T>();
}
public Set<List<T>> getListSet() {
return new HashSet<List<T>>();
}
}
and I have a DummyClass<?> dummy,
I can do
List<?> list = dummy.getList();
without any errors.
However,
Set<List<?>> listSet = dummy.getListSet();
gives the compile error:
Type mismatch: cannot convert from Set<List<capture#1-of ?>> to Set<List<?>>
for the line assigning dummy.getListSet().
Why can't I assign dummy.getListSet() to a Set<List<?>>?
However you can do following:
Set<? extends List<?>> listSet = listSet = dummyClass.getListSet();
See the excellent article Generics gotchas.
First is important to know, that the compiler replace ? operator with Object class. So when you write this:
DummyClass<?> dummy
your class definition will look like this:
public class DummyClass<Object>
and methods like this:
public List<Object> getList() {
return new ArrayList<Object>();
}
public Set<List<Object>> getListSet() {
return new HashSet<List<Object>>();
}
You can write
List<?> list = new List<Object>();
but not
Set<List<?>> set = new HashSet<List<Object>>();
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);
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.