A java class contains an instance variable which is a List.
I need to set the type of object that this List holds in a String variable.
private List<VARIABLE> myList;
String VARIABLE = "BasicDegreeClass";
Is this allowed to do in JAVA If so, how can this be achieved?
Thanks in advance
First, you will have to create a List where T is the Type of objects contained in the list.
So, your code should read as
private List<T> myList;
From the javadoc,
<T> the type of elements in this list.
In your case, the compiler will not know the type of elements that is to be added to your list and hence it won't work.
However you can use List<Object> as an alternate, but that is a generally code-smell in long run and very difficult to maintain
It kills the idea of generics.
Makes your code prone to ClassCastException.
In a perfect world and even if you are safe while adding elements,
you will need to suppress warning everywhere and need to cast back to
the type.
Proper Solution : You can write an interface, which all your objects of the ArrayList will adhere to. Proceed with something like
List<'YOUR INTERFACE TYPE HERE'> myList = new ArrayList<>();
Don't you need to worry of the object type inside the list. Hope this helps!
If you are too specific to save in String, here is a workaround.
public static <T> List<T> getCastedList(List<Object> objList, Class<T> clazz) {
List<T> newList = new ArrayList<T>();
if (objList != null) {
for (Object object : objList) {
if (object != null && clazz.isAssignableFrom(object.getClass())) {
newList.add((T) object);
}
}
}
return newList;
}
And call this as
getCastedList(myList, Class.forName(VARIABLE));
It would be better to use generics like this
private List<T> myList;
documentation here
but it is possible to use a string to represent a class name or act as a unique identifier, given you support this yourself
You can create List only with class not primitive types or its values.
Example:-
List<Integer> a = new ArrayList<>();
List<YourObject> obj = new ArrayList<>();
But if your will try with primitive types then you will get.
Related
I would like to create a generic method with a return type that contains a generic element sent in to the method.
This works fine as long as the input argument is of exact same type as the generic type. However I would like it to be possible to send an extension of the generic type.
Basically, I would like to create a method, createList, that would work for both of these calls:
List<Object> list = createList("foo");
List<String> list2 = createList("bar");
This generic method below works fine for the second call, but not for the first one.
private static <T> List<T> createList(T element) {
List<T> list = new ArrayList<>();
list.add(element);
return list;
}
For the second call I get a compilation error saying "Incompatible types. Required Object. Found String".
Below is the non-generic version which works fine for the first call, but not for the second:
private static List<Object> createList(Object element) {
List<Object> list = new ArrayList<>();
list.add(element);
return list;
}
Same compilation error here as on the other version but this time String is required, and Object was found.
Is it possible to create a method (preferrably using generics) in a way that both these calls would work? (using Java 7)
There were some type inference changes in Java 8 that fix this problem. So the straightforward solution is to update.
If you can't or don't want to update to Java 8, you can also provide the generic type explicitly:
List<Object> list = EnclosingClass.<Object>createList("foo");
Where EnclosingClass is the class that declares createList.
I'm doing something similiar, and solved the problem using a method like this.
Also this is not limited to any certain "Type" of Elements. It allows Every Object and/or primitive. IT also gives you a one-liner to fill a created list with some elements.
#SafeVarargs
private static <T extends Collection<S>, S> T makeList(T collection, S... objects) {
Collections.addAll(collection, objects);
return collection;
}
//example:
List<String> list1 = makeList(new LinkedList<String>(), "foo", "bar");
List<Integer> list2 = makeList(new ArrayList<Integer>(), 1,2,3,4);
I'm new at posting questions here, but have been looking since yesterday for a solution for this and couldn't find. Would really appreciate the help.
I have two lines, at which I'm trying to put generic elements inside a list and get a type mismatch for sending Long elements to List.
List<Long> returnedPages = m_algo.getElement(Arrays.asList(pageIds));
List<Long> pagesNotInRam = new ArrayList<>();
List<Long> pageIdsToHandle = m_algo.putElement(pagesNotInRam, pagesNotInRam);
m_algo is defined
private IAlgoCache<Long, Long> m_algo;
and IAlgoCache works with generic types
public interface IAlgoCache <K, V> {
public V getElement(K key);
public V putElement(K key, V value);}
Can I make this work? Should I work in some sort of loop?
There are several problems with your code. For example
public V getElement(K key); // takes an object as an argument (Long in your case)
m_algo.getElement(Arrays.asList(pageIds)); // you pass a list of objects (I suppose longs)
And even if you fix that issue and pass a proper key later you are trying to assign a Long object to a List. That's why it complains - assigning and object to a collection cannot be done because they are basically different types.
List<Long> returnedPages = m_algo.getElement( properKey ); // Problem
Try with:
List<Long> returnedPages=new ArrayList();
returnedPages.add(m_algo.getElement( properKey));
The problem with putElement is the same. You just need to distinguish between an object and an array or collection of objects. Even if they have the same type they are not interchangeable.
I've read a few topics which cover certain questions about generics, such as their relationship with raw types. But I'd like an additional explanation on a certain line found in the Java SE tutorial on unbound generics .
According to a sentence :
The goal of printList is to print a list of any type, but it fails to achieve that goal — it prints only a list of Object instances; it cannot print List<Integer>, List<String>, List<Double>, and so on, because they are not subtypes of List<Object>.
If I understand well this sentence; the difference between List<?> and List<Object>, is that we can use the type argument List<String> or List<Integer> by implementing the former. While if we implement the later, we can only use the type argument List<Object>. As if List<?> is an upper bound to Object namely List<? extends Object>.
But then the following sentence confuses me, in the sense that according to what I previously understood, List<Object> should only contain instances of the class Object and not something else.
It's important to note that List<Object> and List<?> are not the same. You can insert an Object, or any subtype of Object, into a List<Object>. But you can only insert null into a List<?>.
There are two separate issues here. A List<Object> can in fact take any object as you say. A List<Number> can take at least Number objects, or of course any subclasses, like Integer.
However a method like this:
public void print(List<Number> list);
will actually only take a List which is exactly List<Number>. It will not take any list which is declared List<Integer>.
So the difference is List<?> will take any List with whatever declaration, but List<Object> will only take something that was declared as List<Object>, nothing else.
The last quote simply states, that List<?> is a list for which you literally don't know what type its items are. Because of that, you can not add anything to it other than null.
The sentence that is confusing you is trying to warn you that, while List<?> is the super-type of all generic lists, you cannot add anything to a List<?> collection.
Suppose you tried the following code:
private static void addObjectToList1(final List<?> aList, final Object o ) {
aList.add(o);
}
private static void addObjectToList2(final List<Object> aList, final Object o ) {
aList.add(o);
}
private static <T> void addObjectToList3(final List<T> aList, final T o ) {
aList.add(o);
}
public static void main(String[] args) {
List<String> testList = new ArrayList<String>();
String s = "Add me!";
addObjectToList1(testList, s);
addObjectToList2(testList, s);
addObjectToList3(testList, s);
}
addObjectToList1 doesn't compile, because you cannot add anything except null to a List<?>. (That's what the sentence is trying to tell you.)
addObjectToList2 compiles, but the call to it in main() doesn't compile, because List<Object> is not a super type of List<String>.
addObjectToList3 both compiles and the call works. This is the way to add elements to a generic list.
For practicing purposes I am trying to write a general method to display the elements of an ArrayList by calling its .toString() method. Let's please assume .toString() does what I want it to do.
I came up with this solution below where my input ArrayList is of type Object:
public void printArralyList(ArrayList<Object> list){
for(Object o:list){
System.out.print(o.toString());
}
System.out.println();
}
However it would not work!
printArralyList(new ArrayList<Integer>(Arrays.asList(1,2,3,5,8,13,21)));
The compilation error I get is
The method printArralyList(ArrayList<Object>) is not applicable
for the arguments (ArrayList<Integer>
how can I address that?
An ArrayList<Integer> is not an ArrayList<Object>, even though an Integer is an Object.
You need a wildcard in your method's parameter, because you don't care what type the generic type parameter is.
public void printArralyList(ArrayList<?> list){
Incidentally, you can have your method take a List instead of an ArrayList, and there would be no need to wrap the return of Arrays.asList in an ArrayList:
public void printArralyList(List<?> list){
and
printArralyList(Arrays.asList(1,2,3,5,8,13,21));
would work.
You dont need Generics or wildcard. All you need is a simple method which does not specify any type for the argument so that you can pass in an ArrayList of anytime.
public void printArralyList(ArrayList list){
for (Object o:list){
System.out.print(o.toString());
}
System.out.println();
}
The reason for the error was explained by rgettman in https://stackoverflow.com/a/21996188/
However, if it is for practicing purposes, you should consider practicing polymorphism and programming to an interface
public static void printIterable(Iterable<?> iterable)
{
for (Object object : iterable)
{
System.out.print(object);
}
System.out.println();
}
This can be used with an ArrayList<Integer> parameter, as well as with an LinkedHashSet<JComponent>, or anything else that implements the Iterable interface....
Answering your question.
The declaration ArrayList does not equal to ArrayList. Even if an Integer is delivered from Object in type hierarchy.
Important thing to remember is that when you declare Collection<String> myStrings, you tell to compiler, that to variable myString can be assigned only instances of class that are created upon String type and are Collections.
Collection<Object> myObjects;
myObjects = new ArrayList<String>(); //Exception
myObjects = new HashSet<String>(); //Exception
myObjects = new HashSet<Object>(); //Valid
myObjects = new ArrayList<Object>(); //Valid
myObjects = new ArrayList<Integer>(); //Exception
To solve problems like that, java provide set of Wildcars that allow you to pass this.
There are three type of will card that support various variances.
<? extends T> - Covariance
<? super T> - Contravariance
<?> - Invariance/
The rule about them is called PECS
As we want to consume the list elements, to remove the compilations errors you should use Covariance.
Collection<? extends Object> myObjects;
myObjects = new ArrayList<String>(); //Valid
myObjects = new HashSet<String>(); //Valid
myObjects = new HashSet<Object>(); //Valid
myObjects = new ArrayList<Object>(); //Valid
myObjects = new ArrayList<Integer>(); //Valid
As in Java every class is delivered from object so <? extends> is functionally equal to <?>, and that is what rgettman has proposed as answer
The collection framework in Java is supported with generics. You should get familiar with them to fully benefit from the framework.
A different way to solve is is to benefit from generic methods like this:
public static <T> void printList<Iterable<T> iterable) {
for(T element : iterable){
System.out.printf("%s ",element);
}
System.out.println();
}
Why static ?
The call to static method are faster and this method is not related to any class member.
What is ?
This is declaration of an generic method. It allow you to define the value for generic parameter. And Java is so keen that it can extract it by itself is most cases in version 7.
If you call the method with Iterable<String> then the value of T will be String if Iterable then `Integer'.
Why Iterable ?
The Iterable is a simple interface that allows you to use for-each look. This mean you will be able to iterate through all object that classes definition implements it.
Why printf ?
The printf function use Formatter, the benefits from it are two
- In case when instance of element is assigned with null, you will not get null pointer exception that will occur if you call it o.toString().
What is missing ?
In that implementation is still missing two things
- The input validation
- The proper output format that will separate the elements with a coma.
public class MyGraph<V,E> extends SparseMultigraph<V,E>{
private ArrayList<MyNode> myNodeList;
public MyNode getNode(int nodeId){
myNodeList = new ArrayList<MyNode>();
myNodeList = (ArrayList<MyNode>)this.getVertices();
int i;
The following are the error msg:
Exception in thread "main" java.lang.ClassCastException:
java.util.Collections$UnmodifiableCollection cannot be cast to
java.util.ArrayList...
Can anyone help?
As other people have mentioned, ArrayList has a constructor that takes a collection of items, and adds all of them. Here's the documentation:
http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html#ArrayList%28java.util.Collection%29
So you need to do:
ArrayList<MyNode> myNodeList = new ArrayList<MyNode>(this.getVertices());
However, in another comment you said that was giving you a compiler error. It looks like your class MyGraph is a generic class. And so getVertices() actually returns type V, not type myNode.
I think your code should look like this:
public V getNode(int nodeId){
ArrayList<V> myNodeList = new ArrayList<V>(this.getVertices());
return myNodeList(nodeId);
}
But, that said it's a very inefficient way to extract a node. What you might want to do is store the nodes in a binary tree, then when you get a request for the nth node, you do a binary search.
Try this code
Convert ArrayList to Collection
ArrayList<User> usersArrayList = new ArrayList<User>();
Collection<User> userCollection = new HashSet<User>(usersArrayList);
Convert Collection to ArrayList
Collection<User> userCollection = new HashSet<User>(usersArrayList);
List<User> userList = new ArrayList<User>(userCollection );
public <E> List<E> collectionToList(Collection<E> collection)
{
return (collection instanceof List) ? (List<E>) collection : new ArrayList<E>(collection);
}
Use the above method for converting the collection to list
The following code will fail:
List<String> will_fail = (List<String>)Collections.unmodifiableCollection(new ArrayList<String>());
This instead will work:
List<String> will_work = new ArrayList<String>(Collections.unmodifiableCollection(new ArrayList<String>()));
More information needed for a definitive answer, but this code
myNodeList = (ArrayList<MyNode>)this.getVertices();
will only work if this.getVertices() returns a (subtype of) List<MyNode>. If it is a different collection (like your Exception seems to indicate), you want to use
new ArrayList<MyNode>(this.getVertices())
This will work as long as a Collection type is returned by getVertices.