Casting issue with ArrayList toArray() method - java

In one class I have constructor which looks like:
Class(int x, int y, int[] moves);
In other class which creates those objects I have moves stored in ArrayList. Moves are numbers. So when this class decides ti create new object it must first convert this ArrayList into array. So I tried something like this:
new Object(0, 0, (int[])moves.toArray(int[moves.size()]);
But it doesn't work. How should it be done properly?

The result of calling toArray() on an ArrayList is never an int[]. You can't have an ArrayList<int> in Java due to the way generics works. At best it would be an Integer[], which you'd then need to convert. Note that even though you can convert from Integer to int, you can't cast an Integer[] to an int[]. Something has to loop over the values.
You could just do it directly:
int[] values = new int[moves.size()];
for (int i = 0; i < values.length; i++) {
values[i] = moves.get(i);
}
Alternatively could create an Integer[] and then convert from that - but why do the copying twice?

Related

Changing the number of dimensions an Java array has

Is there a way of changing the number of dimensions an array has, i.e making this
int[][] i = new int[3][3];
but using it like this
getArray(i); //where getArray only accepts one dimensional arrays
?
You cannot change the number of dimensions in a Java array or array type.
But you can make use of the fact that a Java array is an object ... and subtyping .. and declare a getArray method like this:
Object getArray(Object[], ...) { .... }
You can call this method on a int[][] instance, but a runtime typecast is needed to cast the result to an int[].
For example:
Object getArray(Object[] array, int i) { return array[i]; }
int[][] big = new int[3][3];
int[] slice = (int[]) getArray(big, 0);
On the other hand, if you are really asking about how to flatten a multi-dimensional array into a 1-D array, the getArray method needs to allocate a new array, fill it from the original and return it.
Note you would be returning a brand new array that is unconnected to the original one. And copying an N x N .... x N array is expensive.
For more details: Flatten nested arrays in java
Java is statically-typed language. This means that you cannot change a variable's type at runtime. But in this particular case you can simply use the following invocation:
getArray(i[2]); // put anything between 0 and (outerArrayLength-1) instead of 2 here

Create empty array without using List<object>

If I want to create an "unlimited" array I know I can use a list (There is a lot of information on this and other forums)
But what if I don't want to make a list? Is there another way?
Because I want to use a float array in another function and it's kind of a hassle to use a list in this case.
This is what I wrote so far with the listing
List<Float> listfloat = new ArrayList();
listfloat.add((float)0.1); //example
listfloat.add((float)1.2);
float data[]= new float[listfloat.size()];
for(int i = 0; i < listfloat.size(); ++i)
{
data[i] = listfloat.get(i);
}
return data ;
But I would prefer something like this
float data[]; //unknown size
for(i=0 ; i< sizeiwant; i++)
{
data[i] = mydata;
}
return data ;
I know that it will work! I just want to optimise my coding =)
Thank you for reading =)
There are 2 ways you can do this:
You could convert a list to an Array using list.ToArray()
You could dynamically resize the array by changing the size of the array every time you add an element to the array. Here is how you would do that:
//initialize array of size 10.
int[] array=new int[10];
//make copy of array
int[] arrayCopy=array.clone();
//expand array size by 1
array=new int[array.length+1];
//give value to new array index
array[array.length-1]=0;
//copy values from 'arrayCopy' to array
for(int x=0;x<arrayCopy.length;x++){
array[x]=arrayCopy[x];
}
Hope this helped.
With the information you provided I would recommend to use an Array and create a method that is called when your array is full and returns a copy of the original array with more space in this way is you are kind of simulating dynamic size allocation.
Arrays in java are fixed-size, so your second piece of code is never going to work.
If you want a data type that can resize, you should use an ArrayList. On the other hand, there are times when using primitive array like a float[] is quicker and more convenient.
As a result, the need to convert between List<Float> and float[] in the way you do it in the first block of code is fairly common, and there is no way to do it in one line (unless you use an external library).
I advise writing a utility method to do the conversion
public static float[] listToArray(List<Float> list) {
int size = list.size();
float[] temp = new float[size];
for (int i = 0; i < size; i++)
temp[i] = list.get(i);
return temp;
}
(This method could be improved, as it has poor performance for a LinkedList where get is linear).
Annoyingly, you need 8 methods like this for the 8 primitive types, and 8 methods to do the conversions in the other direction. As things stand at the moment, there is no way to write generic code over primitive types, so code duplication like this is common.

Why java does not autobox int[] to Integer[]

When I do the following,
arrayList1 - contains one element and it is an int[].
arrayList2 - not compiling (Error : The constructor ArrayList<Integer>(List<int[]>) is undefined)
arrayList3 - contains 7 elements and they are Integer objects
Here's the code:
int[] intArray = new int[]{2,3,4,5,6,7,8};
ArrayList arrayList1 = new ArrayList(Arrays.asList(intArray));
ArrayList<Integer> arrayList2 = new ArrayList<Integer>(Arrays.asList(intArray));
Integer[] integerArray = new Integer[]{2,3,4,5,6,7,8};
ArrayList<Integer> arrayList3 = new ArrayList<Integer>(Arrays.asList(integerArray));
Question :
Why doesn't the compiler auto-box the elements in the int[] to Integer and create an ArrayList<Integer>? What is the reason behind this? Is that my stupidity or some other reason?
The difference is int[] is itself an Object, whereas Integer[] is an array of references to Integer object.
Arrays.asList(T...) method takes variable arguments of some type T with no upper bounds. The erasure of that method is Arrays.asList(Object...). That means it will take variable number of arguments of any type that extends from Object.
Since int is not an Object, but a primitive type, so it can't be passed as individual element of T[], whereas int[] is an Object itself, it will go as first element of the T[] array (T... internally is a T[] only). However, Integer[] will be passed as T[], with each reference in Integer[] passed as different argument to T[].
And even if you would argue that compiler should have done the conversion from each element of int[] array to Integer, well that would be too much work for the compiler. First it would need to take each array element, and box it to Integer, then it would need to internally create an Integer[] from those elements. That is really too much. It already has a direct conversion from int[] to Object, which it follows. Although I have always wished Java allowed implicit conversion from int[] to Integer[], that would have made life simpler while working with generics, but again, that's how the language is designed.
Take a simple example:
Object[] array = new Integer[10]; // this is valid conversion
Object[] array2 = new int[10]; // this is not
Object obj = new int[10]; // this is again a valid conversion
So, in your code Arrays.asList(intArray) returns a ArrayList<int[]> and not ArrayList<Integer>. You can't pass it to the ArrayList<Integer>() constructor.
Related:
int[] and Integer[]: What is the difference?
An int[] is not the same as an Integer[].
An array has as associated Class object. The class object for an array of primitive ints is [I. The class object for an array of Integer is [Ljava/lang/Integer.
An array is itself an object, so converting between two objects of the same type is an identity conversion. Converting between two different typed objects isn't - and int[] and Integer[] are definitely different, as evidenced by the bytecode above.
Lastly, bear in mind that autoboxing would only really apply if there was an associated boxing conversion.
Technically it is possible to do it of course. However autoboxing/unboxing of primitive type array to wrapper type array is more than what you expect.
First look into the auto-boxing/unboxing of Java: What it does is simply a syntax sugar to save you typing the primitive wrapper code. e.g.
Integer i = 10;
Compiler knows that it is expecting an Integer, but int present instead. Therefore what the compiler doing is translating your code to:
Integer i = Integer.valueOf(10);
It does similar thing for unboxing: when in situation that it expects int but Integer is present, compiler replace it with varName.intValue()
Back to array. There are two problems we can forsee:
The first problem is, there is no straight-forward way to transform from an int array to an Integer array. You may argue that the compiler can transform
int[] intArray = ....;
Integer[] wrapperArray = intArray ;
to
Integer[] wrapperArray = new Integer[intArray.size()];
for (int i = 0; i < intArray.size(); i++) {
wrapperArray[i] = Integer.valueOf(intArray[i]);
}
but that seems too much for a syntax sugar.
The second big problem is, when you are passing it as a parameter to a method, if autoboxing/unboxing happens for array, instead of reference of original array is passed, you are now passing the reference of a copy of the original array. In case you are changing the content of array in your method, the original array will not be affected. That can bring you lots of surprises.
e.g.
void foo(Integer[] arr) {
arr[0] = 0;
}
// invoking foo in some code:
int[] intArr = new int[]{9,8,7,6};
foo(intArr);
// intArr[0] will still be 9, instead of 0
Because int[] and Integer[] both are objects. First will hold primitive int values, which are not of type Object while second will store references of Integer objects, which are of type Object.
arrayList1 is really a List of size one.
http://ideone.com/w0b1vY
arrayList1.size() = 1
arrayList3.size() = 7
The int[] is being cast to a single Object. That Object cannot be cast to Integer.

Setting a generic ArrayList to zeros

I have an ArrayList. I would like to set each element of it to 0. Right now I have:
ArrayList <T extends Number> arr = new ArrayList();
for(int i = 0; i < some_other_array.size(); i++)
{
arr.add(0)
}
The compiler complains that
error: no suitable method found for set(int,int)
arr.add(0);
^
method ArrayList.set(int,T) is not applicable
(actual argument int cannot be converted to T by method invocation conversion)
where T is a type-variable:
T extends Number
It cannot be done. The method signature for is
public T ArrayList<T>.set(int index, T element)
Even though the constraint on T is that it extends Number, it does not mean that it can be constructed from a number.
Consider, for example,
class FortyTwo extends Number {
public byteValue() { return 42; }
public intValue() { return 42; }
// etc
}
What would you expect the initialization routine to do to an ArrayList<FortyTwo> ?
Just change your list declaration to
ArrayList<Number> arr = new ArrayList<Number>();
arr will be capable of holding anything extending Number (which is what you want, I assume).
Now, when you do
arr.set(i, 0)
that 0 will be autoboxed to an Integer. (See for yourself, add 0 and print arr.get(0) instanceof Integer.)
If you wanted to add doubles or longs for instance, you could use the literals 0d and 0L, respectively.
This should work for your case: arr.set(i, Integer.valueof(0));
Or you can reuse this handy standard API: Collections.fill(arr, Integer.valueof(0));
Why you want to set the value to 0, it will be automaticaly zero as ArrayList object will be instantiated. So the code will be useless as the size will be zero at the time so loop will not be executed.
Well, I think you're a little confused about how ArrayList actually works. When you create an ArrayList, it's always empty. Even if you specify a size:
ArrayList<Integer> arr = new ArrayList<Integer>(20);
That 20 just means "initial capacity", not "starting number of elements". As a result, set will never work because there are simply no elements. Even if you fix your compiler issue like this:
arr.set(i, Integer.valueOf(0));
Or like this:
ArrayList<Number> arr = new ArrayList<Number>();
It's not even going to do anything because arr.size() is zero, so the for loop won't even run.
The key here is that ArrayList is not an actual array. It wraps an array, and will expand its inner array when it has too many elements. In other words, I can't do this:
ArrayList<Integer> arr = new ArrayList<Integer>(20);
arr.get(0); // Throws an out of bounds exception
Now, that being said, if you want to start with 20 zeroes in your ArrayList, you can use the add method in your loop and i < 20 instead:
for(int i = 0; i < 20; i++) {
arr.add(Integer.valueOf(0));
}
This will add 20 zeroes to arr. Your code, even after fixing the error, will not.
Try changing the declaration of your ArrayList to
ArrayList<Integer> arr = new ArrayList<Integer>();
The Integer class supports auto-boxing, while the Number class does not. Also, the add() method may be more applicable.
You can try this (to the best of my knowledge, you cannot add primitive types to ArrayList):
ArrayList<Integer> arr = new ArrayList<Integer>();
for(int i = 0; i < someNumber; i++)
{
arr.add(0);
}
Remember that when size is 0 because it does not have any default values and the capacity is what you should be looking at (You can set the capacity in the constructor.)

Java int[][] array object

I have defined an int[][] object. Because it is an object, if i send it to a method as a parameter, it will only send it's reference, so any changes to the array in the method, will influence it in the main program. So i would like to make a clone of this object inside the method, but i'm not sure how to accomplish this.
I was thinking of something like so:
private void myMethod( int[][] array )
{
//Define our temporary array (clone)
int[][] newArray = new int[3][3];
//Go through the elements of the array
for .... row = 0; row < ..; row++
for ..... col = 0; col < ..; col++
//Copy individual elements from one array to another
newArray[row][col] = array[row][col];
}
but will the above code copy each element from array into newArray as value (so... a clone of the item), or just the reference?
If so, how can this be accomplished. If i were to use ArrayLists instead of int[][] objects, there is the clone() method or something like that, but i haven't got that method for int[][] objects :(
Also, if i'm not mistaken if i do this inside the method newArray = array , that will copy just the reference again, so both will point to the same int[][] object :(
P.S. I know i could just test this, but i'd like to discuss it with you guys a bit, and see what's what exactly.
but will the above code copy each element from array into newArray as value (so... a clone of the item), or just the reference?
You're copying each element of the array, and each element is an int, so you're fine. The new array will be completely independent of the original.
Note that if instead you'd done:
int[][] newArray = new int[3][];
for (int i = 0; i < 3; i++) {
newArray[i] = array[i];
}
... then that would just have copied references to the three existing int[] arrays into newArray. But you've allocated a completely new set of arrays (one int[][] and 3x int[]) so it's all independent.
You could use clone() on the matrix and on each array corresponding to a row in the matrix, it will work without problems because you're cloning a matrix of primitive values, like this:
int[][] matrix = new int[3][3];
// ... matrix gets filled ...
int[][] copy = matrix.clone();
for (int i = 0; i < matrix.length; i++)
copy[i] = matrix[i].clone();
The above will create a copy matrix which is independent of matrix, meaning that you can change the values of the copy without affecting the original.
Primitive types, such as int, are not reference types. Thus, going through all the items and copying them one by one will make a copy-by-value.
In short, your code is correct.
int is a primitive type, you always pass them around as value, not as reference, so you code will indeed create a new copy of the array.
You might want to consider using Arrays.copyOf(), it may be faster.

Categories