beware: non-experienced coder...
I have an arraylist (named a) of arraylists (named b). b is an arraylist of characters. When I try to get a single character from the b by doing
a.get(0).get(0);
it gives me an error saying I'm giving it a object, not a character.
Because the second get is returning an Object, the first get seems to return the ArrayList (or a List) properly. The most likely explanation is that you have a partially generic, partially raw ArrayList, presumably of the type ArrayList<ArrayList>. The generic type parameter ArrayList is itself a raw type, meaning it will return an Object upon a call to get. Another possibility is that you have an ArrayList<ArrayList<Object>>.
Fully specify the generic type, nesting generics all the way down to the scalar type.
ArrayList<ArrayList<Character>> a;
That is nature of generics. If you don't specify type of elements in your a list in your case using
List<List<Character>> a;
but instead you will use raw type
List a;
compiler can only assume that you are storing Objects so result of get() will also be assumed to be Object which doesn't have any get()
a.get(0).get(0)
//^-this method can't be invoked from reference of Object type
Related
As I am new to Java, I have few doubts regarding Java generics behavior. Here I have implemented own List functionality using native list as wrapper. Below is the code,
ListWrapper<String> li = new ListWrapper<String>(); // wrapper for native list implemented
li.add(“Hello”);
Iterated the elements in the list by converting the list items to array and used in foreach loop.
//Method which used to convert as array in ListWrapper.
public T[] toArray() {
return (T[]) _list.toArray(); // _list is the native list (i.e) java.util.List which converts list items to object[] array.
}
On using this method in for-each loop faced class-cast exception only on compiled class(.jar) but works properly on attaching the source.
for(Object s : li.toArray()) { // Class cast exception occurred here.
System.out.println(s);
}
My understanding:
toArray() in the for-each loop will be called once and iterator will be called implicitly to iterate over the elements. As I have casted the toArray() as T[] (here T will be of String), hence Iterator will try to access the object[] array. So, class cast exception of [Ljava.lang.Object; cannot be cast to [Ljava.lang.String occurred. Please correct me if am wrong.
Also, I would like to know why the same code works properly while running by attaching the source. Can anyone clarify for me?
In Java, an array object knows its component type at runtime, and so when creating an array, you need to provide the component type at runtime. On the other hand, an instance of a generic class does not know its component type at runtime. For a List<T> instance, it doesn't by default know what T is at runtime, so there is no way it can create an array with a runtime component type of T.
List's toArray() method with no arguments will always create an array with a runtime component type of Object. This array will always have the runtime class Object[]; it cannot be String[] or Integer[] or whatever. A variable of type String[] cannot point to this object, since Object[] is not a subtype of String[], so it will cause a ClassCastException. (And by the way, all this was true before there was generics; generics improved some of the signatures, but the runtime behavior is the same.) Your cast to T[] is fundamentally unsafe.
When you do unsafe casts in generics, it can cause ClassCastExceptions in other places where there isn't an explicit cast. It will not cause a ClassCastException where you cast to T[], because T is erased to Object (T's upper bound), so the erased code is just casting Object[] to Object[]. However, the fact that the method returns T[] means that the caller of the method, if they have a specific type for T, can cast the return result. So here, the caller expects li.toArray() to return type String[] (since li has type ListWrapper<String>, so T is String, and ListWrapper.toArray() returns T[]). So it can insert a cast of the result to String[], even though you don't see a cast in the code. That is why you get a ClassCastException there.
(Now, you could argue that technically it doesn't need to cast to String[], since it's used in a foreach loop, and each element is assigned to a variable of type Object, so it is valid to leave li.toArray() as Object[] and not cast. But it is also permissible for the compiler to cast it anyway; and here, the compiler decided to insert a cast.)
List has another toArray() method, which takes one argument of array type. This method will either use the passed array object to store the results, or extract the runtime component type out of the passed array object, and create a new array object with the same runtime component type. So the returned array object will have the same runtime class as the passed array object. So you can use this toArray() method to get an array object whose runtime class is a more specific array type than Object[], but you will have to give an array object of the right type at runtime.
If you want to implement a type-safe .toArray() method in your ListWrapper class, you would have to do something like what List does -- either it must always return an array with runtime class Object[], and therefore it must be returned in type Object[]; and/or it must take in an array object as an argument to extract the runtime component type from, to create an array object of the right component type.
Based on the information provided in the link, it says that:
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<?>.
What is the use of using List<?> when only null can be inserted?
For example,
methodOne(ArrayList<?> l): We can use this method for ArrayList of any type but within the method we can’t add anything to the List except null.
l.add(null);//(valid)
l.add("A");//(invalid)
You use the unbounded wildcards when the list (or the collection) is of unknown types.
Like the tutorial says, it's used when you want to get information about some list, like printing its content, but you don't know what type it might be containing:
public static void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}
You shouldn't use it when you want to insert values to the list, since the only value allowed is null, because you don't know what values it contains..
You can get elements from your list.
List<?> is usually used as a type for a list of unknown-typed objects returned by a method or so, where you read elements from, rather than adding them.
List<?> is quite different. If we try and add objects into a List<?>, even if the object is of type Object, we can't do it. It says,
add(capture<?>) in java.util.List cannot be applied to (java.lang.Object)
Now that might seem a bit restrictive. If you can't have any values being passed as parameters, which is what I mean when I say put into a list, then, what can you do with it?
Well, let's see why that restriction exists. To begin with, we know that arrays are covariant. So what that means is we could take an array of Strings and put that into an Object Array.
So here, if we take that first object and we assign it to a random String, everything will be fine. And if we assign it to a new Object, if we add that in, then we will get an ArrayStoreException
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Object
because of the unsafety of covariant arrays.
Well, in the case of List<?>, what the Java compiler is trying to do for us by banning us from adding values into a List<?> or a List<? extends Object> is put us into a position where this type can only be safely used. And in fact, the only value that you are allowed to put into a List<?> is the null value because null can be coerced into any type.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized
In order to save an ArrayList with payments done by one member I want to change the List of Payment ID's into a string, so I created the following method:
public String fromArraytoString(ArrayList items){
JSONObject json = new JSONObject();
json.put("uniqueArrays", new JSONArray(items));
return json.toString();
}
But I get the following warning:
ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized
Can anyone explain me why?
You definitely should read this tutorial on Java generics:
http://docs.oracle.com/javase/tutorial/java/generics/
In a nutshell:
Many Java classes and types (called generic classes or generic types), typically collections, have so called type parameters, such as E in ArrayList<E> (E is just an arbitrary chosen name, other classes name it as T or whatever):
public class ArrayList<E> extends ... {
public E get(int index) { ... }
public boolean add(E element) { ... }
// other methods...
}
Now, when you create an instance of such class, you define a concrete value of the type parameter, for example String (E can usually be evaluated to whatever type you want):
ArrayList<String> stringList = new ArrayList<String>();
From now on, all the Es are "replaced" by String for the stringList variable, so you can add only Strings to it and get only Strings from it. The compiler checks for you that you don't mistakenly add an object of another type:
stringList.add(Integer.valueOf(1));
// compile error - cannot add Integer to ArrayList of Strings
However, because generics were added to Java 5, it is still possible to write code without them for backwards compatibility. So you can write:
ArrayList list = new ArrayList();
But you lose all the type checking benefits. Es in method signatures become simply Objects.
list.add(Integer.valueOf(42)); // adding an Integer
list.add("aaa"); // adding a String
Object something = list.get(0); // unknown type of returned object, need to cast
Integer i0 = (Integer) something; // this unsafe cast works...
Integer i1 = (Integer) list.get(1); // but this fails with a ClassCastException
// because you cannot cast a String to Integer
The fact that using a raw type (that is a generic type with its type parameters omitted) is unsafe, is the reason for the warning you've got. Instead of just ArrayList, use ArrayList<String> or ArrayList<Integer> or whatever the type of your items is.
What kind of objects are stored in the ArrayList? You need to add it to the declaration. It's always
ArrayList<Type>
So if it's a list of JSONObjects, you would put
ArrayList<JSONObject>
Hope that helps.
JsonArray's constructor expects to receive a generic type Collection with parameter T, while items's type is ArrayList without type specified(i.e raw type). You may check this question to get some idea about raw type: What is a raw type and why shouldn't we use it?
Solution 1(recommended): pass items with paramter T or specify concrete type such as String. This question might help you in your specific problem: convert ArrayList<MyCustomClass> to JSONArray.
Solution 2: add #SuppressWarnings("unchecked") before the method fromArraytoString.
This is not recommended, but you can refer to this question: What is SuppressWarnings ("unchecked") in Java?
This is because Java compiler tries to do certain checking for you. The way you have written it you effectively tell compiler you will receive ArrayList of Object's as parameter.
It's simply encouraging you to specify class of objects you will to store in ArrayList. Specifying ArrayList<MyClass> or ArrayList <?> would get rid of the warning. Second version effectively tells compiler that you would pass ArrayList of objects of class not known at compile time.
I think it might be useful for you to read a bit about generics in Java.
http://docs.oracle.com/javase/tutorial/java/generics/
In Java ArrayList<E> implementation base on a array of objects.
Can anybody explain me why implementation of ArrayList<E> uses array Object[] for data storage instead of E[]? What the benefit of using Object[]?
In Java, creating an array of a generic type is not straightforward.
The simple approach does not compile:
public class Container<E> {
E[] arr = new E[3]; // ERROR: Cannot create a generic array of E
}
Replace E with Object, and all is well (at the expense of added complexity elsewhere in the container implementation).
There are alternative approaches, but they present a different set of tradeoffs. For an extensive discussion, see How to create a generic array in Java?
So first of all, realize that the actual runtime type of the array object must be Object[]. This is because arrays know their component types at runtime (different array types are actually different types at runtime), and thus you need to specify the component type in creating the array, but the ArrayList object does not know its type argument at runtime.
That said, the compile-time type of the instance variable could be declared as either Object[] or E[], with different advantages and disadvantages:
If it is declared as Object[]:
private Object[] arr;
// to create it:
arr = new Object[3];
// to get an element:
E get(int i) { return (E)arr[i]; }
The disadvantage of this is that you must cast it to E every time you take something out of it, which means you are basically using it as a pre-generics container.
If it is declared as E[]:
private E[] arr;
// to create it:
arr = (E[])new Object[3];
// to get an element:
E get(int i) { return arr[i]; }
The advantage of this is that you no longer have to cast when you get things out of it -- it provides type-checking on the uses of arr, like generic containers. The disadvantage is that, logically, the cast is lie -- we know we created an object whose runtime type is Object[], and so it is not an instance of E[], unless E is Object.
However, there is no immediate problem with doing this, because E is erased to Object inside the instance methods of the class. The only way a problem can occur is if the object is somehow exposed to the outside of the class (e.g. returned in a method, put in a public field, etc.) in a capacity that uses its type as E[] (which it's not):
// This would be bad. It would cause a class cast exception at the call site
E[] getArray() { return arr; }
But ArrayList, and indeed any properly-designed container class, would never expose an implementation detail such as its internal array to the outside. It would break abstraction, among other things. So as long as the author of this class is aware of not ever exposing this array, there is no problem with doing it this way (save perhaps confusing the next person who sees the code and is unaware of it), and is free to take advantage of the increased type-checking that this way brings.
Considering type erasure (that is, the fact that generics type parameters such as E in your example are deleted at compilation type), I suspect the generated bytecode would be similar in both cases.
From a maintenance point of view, using a type parameter instead of Object would lead to easier to read code (since it would limit casts). But since the API of ArrayList never exposes that "raw" Object array, I suppose it does not make any difference for us mere Java developers :)
I'm looking at an example implementation of a linkedlist consisting of nodes. The set method goes to the input index and sets the value equal to the input value. Additionally, it returns the old value. When he retrieves the old value he always creates a new node object instead of an object of type E. Is that necessary or is that considered good practice? Also are there any efficiency considerations? Example code below
public E set(int idx, E newVal){
//looping code to get to the right node
//Assume variable finger is now a Node object that's at the right index
Node<E> temp = new Node<E>(finger);
finger.setValue(newVal);
return temp.getValue();
//Can I do the following instead?
E temp = finger.getValue();
finger.setValue(newVal);
return temp;
}
No, it's perfectly acceptable to use the generic type parameter (E in this case). There's nothing wrong with your second code sample.
According to the Generics FAQ:
Can I use a type parameter like a type?
No, a type parameter is not a type in the regular sense (different from a regular type such as a non-generic class or interface).
Type parameters can be used for typing (like non-generic classes and interfaces)::
as argument and return types of methods
as type of a field or local reference variable
as type argument of other parameterized types
as target type in casts
as explicit type argument of parameterized methods
Type parameters can NOT be used for the following purposes (different from non-generic classes and interfaces)::
for creation of objects
for creation of arrays
in exception handling
in static context
in instanceof expressions
as supertypes
in a class literal
Assuming that setValue() and getValue() modify the same attribute, the first 3 lines of code will return newVal (they don't make much sense)
temp is a reference to finger, so if you set a new value to an attribute in finger, then it will change in temp.
The last three lines don't have the same behavior, since they return the previous value.
That impl is quite odd. It probably was translated from a C++ impl
Node<E> temp = finger; // C++, copy constructor, default is shallow copy
finger.setValue(newVal);
return temp.getValue();
That would be very cheap for C++.