I have a Vector like so:
Vector myVector = new Vector();
And an ArrayList of a custom class which contains n amount of Strings.
Basically, I add an empty item into the first position in the Vector (myVector.insertElementAt("", 0);), and then add (usually) the rest of the items from the ArrayList (depending on the needs). This Vector then is used as the the DefaultComboBoxModel for a JComboBox.
Now, I get the usual warning References to the generic type Vector should be parameterized.
The items are of type String, but I can't use Vector<String> because adding the items from the ArrayList (using .add()) won't work as:
The method add(String) in the type Vector(String) is not applicable for the arguments (CustomClass).
I can't use Vector(CustomClass) because then insertElementAt throws a wobbler.
So my question is: Is it safe to just use Vector(Object) or not parameterize the type at all?
I could use T and cast everything but would get a type safety error.
I can't use Vector because adding the items from the ArrayList (using .add()) won't work as:
The method add(String) in the type Vector(String) is not applicable for the arguments (CustomClass).
So, you are trying to add things from an ArrayList<CustomClass> to a Vector that you expect only to contain String elements.
If you are using a raw-typed Vector, you can do this, but it will fail down the line if you try to do anything with an element from that Vector that you treat as a String, because it's not.
If you want the Vector to contain Strings, add a String:
myVector.add(thingFromArrayList.toString());
(or some other means of converting thingFromArrayList to a String)
and then you can add the <String> to myVector's type.
Related
I faced a problem yesterday, when I was writing my homework. I finished the homework, but I still don't really understand why my code works. I had to write a sort function that takes an varargs of any comparable generic object as an argument and return the argument. The problem was that I had to return an array of sorted objects. So I had to learn more about varargs lists and arrays.
The function was defined like this.
public <T extends Comparable<T>> T[] stableSort(T ... items)
and inside the function I made a list, which I would sort and do all the work on.
List<T> list = new ArrayList<T>(Arrays.asList(items));
and at the end of the function I was returning list toArray so that it matched the output type T[].
list.toArray(items.clone());
My question is since I already made the list from the varargs, why do I have to do items.clone() inside the toArray function. That seemed like doing two same things to me. I thought arrays.asList() would clone the values of array to list and I don't get why am I doing it again at the end of the code in toArray(). I know that this was the correct way to write it, because I finished the homework yesterday and found out this way from forums of the class, but I still don't understand why.
EDIT
The task required me to create a new array with sorted files and return it instead. Due to Type Erasure, it is not possible to instantiate an array of a generic type without a reference to a class that fits the generic. However, the varargs array has type T, so I should have cloned an array of a type which fits the generic constraints. Which I didn't know how to do in time. So I decided to use list to make my time easier till the deadline.
My question is since I already made the list from the varargs, why do I have to do items.clone()
You are right. Unfortunately, the compiler will be unable to determine the type of the array if you simply use the toArray() method. You should get a compilation error saying Cannot convert from Object[] to T[]. The call to item.clone() is required to assist the compiler in type-inference. An alternate approach would be to say return (T[])list.toArray
That said, I would not recommend either of the approaches. It doesn't really make sense to convert an array to a list and convert it back to an array in the first place. I don't see any significant take-aways that you would even understand from this code.
It seems to me there are a few questions here, that may have come together to create some confusion as to why what needs to be done.
I thought arrays.asList() would clone the values of array to list and I don't get why am I doing it again at the end of the code in toArray().
This is probably just the way it is typed, but it should be made clear that you don't clone the objects in the array, but only make a new List with the references to the objects in the array. The objects themselves will be the same ones in the array as in the List. I believe that is probably what you meant, but terminology can be tricky here.
I thought arrays.asList() would clone the values of array to list...
Not really. Using Arrays.asList(T[] items) will provide a view onto the array items that implements the java.util.List interface. This is a fixed-size list. You can't add to it. Changes to it, such as replacing an element or sorting in-place, will pass through to the underlying array. So if you do this
List<T> l = Arrays.asList(T[] items);
l.set(0, null);
... you've just set the element at index 0 of the actual array items to null.
The part of your code where you do this
List<T> list = new ArrayList<T>(Arrays.asList(items));
could be written as this:
List<T> temp = Arrays.asList(items);
List<T> list = new ArrayList<T>(temp);
The first line is the "view", the second line will effectively create a new java.util.ArrayList and fill it with the values of the view in the order they are returned in by their iterator (which is just the order in the array). So any changes to list that you make now don't change array items, but keep in mind that it's still just a list of references. items and list are referencing the same objects, just with their own order.
My question is since I already made the list from the varargs, why do I have to do items.clone() inside the toArray function.
There could be two reasons here. The first is as CKing said in his/her answer. Because of type erasure and the way arrays are implemented in Java (there are separate array types depending on whether it's an array of primitives or references) the JVM would not know what type of array to create if you just called toArray() on the list, which is why that method has a return type of Object[]. So in order to get an array of a specific type, you must provide an array to the method that can be used at run-time to determine the type from. This is a piece of the Java API where the fact that generics work via type-erasure, aren't retained at run-time and the particular way in which arrays work all come together to surprise the developer. A bit of abstraction is leaking there.
But there might be a second reason. If you go check the toArray(T[] a) method in the Java API, you'll notice this part:
If the list fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this list.
Suppose some code by another dev is using your stableSort method like this:
T[] items;
// items is created and filled...
T[] sortedItems = stableSort(items);
If you didn't do the clone, what would happen in your code would be this:
List<T> list = new ArrayList<T>(Arrays.asList(items));
// List is now a new ArrayList with the same elements as items
// Do some things with list, such as sorting
T[] result = list.toArray(items);
// Seeing how the list would fit in items, since it has the same number of elements,
// result IS in fact items
So now the caller of your code gets sortedItems back, but that array is the same array as the one he passed in, namely items. You see, varargs are nothing more than syntactic sugar for a method with an array argument, and are implemented as such. Perhaps the caller didn't expect the array he passed in as an argument to be changed, and might still need the array with the original order. Doing a clone first will avoid that and makes the effect of the method less surprising. Good documentation on your methods is crucial in situations like this.
It's possible that code testing your assignment's implementation wants a different array back, and it's an actual acquirement that your method adheres to that contract.
EDIT:
Actually, your code could be much simpler. You'll achieve the same with:
T[] copy = items.clone();
Arrays.sort(copy);
return copy;
But your assignment might have been to actually implement a sorting algorithm yourself, so this point may be moot.
You need to use this:
List<T> list = new ArrayList<T>(Arrays.asList(items));
when you want to do an inline declaration.
For example:
List<String> list = new ArrayList<String>(Arrays.asList("aaa", "bbb", "ccc"));
By the way, you didn't have to use return list.toArray(items.clone()); You could have used, for example, return list.toArray(Arrays.copyOf(items, 0));, where you are passing to list.toArray() an empty array that contains none of the arguments from items.
The whole point of passing an argument to the version of list.toArray() that takes an argument, is to provide an array object whose actual runtime class is the actual runtime class of the array object it wants to return. This could have been achieved with items.clone(), or with items itself (though that would cause list.toArray() to write the resulting elements into the original array pointed to by items which you may not want to happen), or with, as I showed above, an empty array that has the same runtime class.
By the way, the need to pass the argument to list.toArray() is not a generics type issue at all. Even if you had written this with pre-generics Java, you would have had to do the same thing. This is because the version of List::toArray() that took no arguments always returns an array object whose actual runtime class is Object[], as the List doesn't know at runtime what its component type is. To have it return an array object whose actual runtime class is something different, you had to give it an example array object of the right runtime class to follow. That's why pre-generics Java also had the version of List::toArray() that took one argument; even though in pre-generics, both methods were declared to return Object[], they are different as the actual runtime class returned is different.
Question: If you have a List and it has String objects, which declaration(s) of your List does not require that objects retrieved using the get method be cast to Strings, before calling a String method? List <Object> a = new ArrayList <Object>();
I. List<Object> a = new ArrayList <Object>();
II. List<String> a = new ArrayList <String>();
III.List a = new ArrayList();
I don't really understand this question. I think you must cast to a String to use it as a String, then it must be a declaration that does not return a String object as a String.
Here's how you should think about the answer: What does each of the following return?
I. and III. are the same thing. Both instances will return a java.lang.Object if you call get. You'll have to cast that to a java.lang.String in order to use it.
Only II. will return a String if you call get, because of the generic declaration.
2 will not require explicit casting. 1 and 3 are effectively the same thing.
The second one.
ArrayList<String> a = new ArrayList <String>();
This means that the arraylist can only hold string type variables. It says string in the pointy brackets. This is called generics and it allows the data you take out to be of the form you specify, in this case a String.
I. and III both are a list of Objects (and I. has a typo on the declaration, the correct class type is "Object"). You can store anything in them, including Strings, but as far as the compiler can tell... they're of type Object, so if you want to call a String method on an object you retrieved with the ArrayList.get(...) method you will have to cast the returned object to String.
II. is a list of Strings (the type of stored objects is specified by the generics part between <...>), the compiler knows the ArrayList will only store Strings, so the ArrayList.get() will return a String directly, without the need for a cast.
You can see an example of this exact thing in the Java Generics Tutorial.
Can someone please explain what the difference between ArrayList<?>, ArrayList and ArrayList<Object> is, and when to use each? Are they all same or does each have some different meaning at the implementation level?
ArrayList<Object> is specifically a list of Objects whereas ArrayList<?> is a list whose concrete type we are unsure of (meaning we can't add anything to the list except null). You would use the latter when the list's type is irrelevant, e.g. when the operation you want to perform does not depend on the type of the list. For instance:
public static boolean isBigEnough(ArrayList<?> list) {
return list.size() > 42;
}
This is all covered in the generics tutorial (see the wildcards section).
Finally, ArrayList with no type parameter is the raw type: the only reason it's even allowed is for backwards compatibility with Java versions under 5, and you should refrain from using it whenever possible.
ArrayList<?> means "an ArrayList instance containing a type which is to be determined"
ArrayList is the class of an ArrayList
An ArrayList<Object> means an instance of ArrayList containing Object types.
This looks like it could be a good write-up on this (and more): http://docs.oracle.com/javase/tutorial/java/generics/types.html
I am working on writing a sudoku solver and I want the grid to be stored as an arraylist of arraylist of ints...each spot will have an arraylist of ints of all possible numbers (or the definite value).
ArrayList<ArrayList<int>> sudoku_board = new ArrayList <ArrayList<int>>();
Java is throwing me an error saying "dimensions expected after token" on the ints.
Generic type parameters require reference types, rather than primitive types. Use
List<ArrayList<Integer>> sudoku_board = new ArrayList <ArrayList<Integer>>();
Also when coding to an interface use the interface as the reference type, in this case List. Everything that appears within the generics should remain as the implementation type due to the non co-variance of generics.
From #assylias comment, a more generic type of list is
List<List<Integer>> list = new ArrayList<List<Integer>>();
This will allow for List implementations types other than ArrayList to be added should refactoring be necessary later.
Use Integer wrapper class instead primitive.
ArrayList wont allow primitive as type argument.
List<ArrayList<Integer>> list= new ArrayList <ArrayList<Integer>>();
Arraylist is used to store objects not primitives, so change the signature accordingly.
I am wondering why did they design the toArray method in ArrayList to take a input of an array in Java?
ArrayList<String> listArray = new ArrayList<String>();
listArray.add("Germany");
listArray.add("Holland");
listArray.add("Sweden");
String []strArray = new String[3];
String[] a = (String [])listArray.toArray(strArray);
To me it appears that, they dont need this input because the instance of the ArrayList itself has enough details to convert the data into an array.
My question is why do they still need the array to be passed in? Thanks.
Two reasons I can think of:
Erasure means that the generic parameters aren't available at runtime, so an ArrayList<String> doesn't know that it contains strings, it's just the raw type ArrayList. Thus all invocations of toArray() would have to return an Object[], which isn't strictly correct. You'd have to actually create a second array of String[] then iterate over the first, casting all of its parameters in turn to come out with the desired result type.
The way the method is defined means that you can pass in a reference to an existing array, and have this populated via the method. In some cases this is likely very convenient, rather than having a new array returned and then copying its values elsewhere.
In your code, the ArrayList can contain anything, not only Strings. You could rewrite the code to:
ArrayList<String> listArray = new ArrayList<String>();
listArray.add("Germany");
listArray.add("Holland");
listArray.add("Sweden");
String []strArray = new String[3];
String[] a = listArray.toArray(strArray);
However, in Java arrays contain their content type (String) at runtime, while generics are erased by the compiler, so there is still no way for the runtime system to know that it should create a String[] in your code.
You need it to get array types other than Object[]. listArray.toArray(new String[3]) shouldn't actually need a cast to String[], but it lets you write into arrays for specific types, rather than the (rather unsafe) approach of just casting Object[] to whatever your type is.
It is so that when you have an non-empty array you want object to be appended to from the arraylist conversion you can do that without having to create a new array, and do post processing of merging it, save resource and extra work.
Read the second paragraph of the javadoc: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/ArrayList.html#toArray(T[])
ArrayList doesn't have enough information given that the "data" itself is stored in buckets of Object arrays. So, if you know "what" kind of items you have in your array list, you can achieve type safety by using this variant of the toArray method.
It is not compulsory to pass an Array as an argument to toArray(), you can directly call ArrayList.toArray()
As we know that Collection framework with generics works with the concept of Type Erasure. So the ArrayList becomes List of Object, so when you convert to array it will give an Object[] if you don't pass any argument.
Because the array into which the elements are to be copied should be specified to the JVM.
See this documentation