Why can you cast int[] to Object, but not to Object[]? - java

So this works:
int i;
Object a = (Object) i;
int[] t;
Object b = (Object) t;
String[] s;
Object[] t = (Object[]) s;
But this does not:
int[] t;
Object[] z = (Object[]) t;
All in all I get the first part (boxing), but I find it highly unintuitive that the second part does not work. Is there a specific reason why (beside String inheriting from Object and int not inheriting from Object)?
Edit:
To refine my question, this also works:
int a = 2;
int b = 3;
int c = 4;
int d = 2;
Object[] o = new Object[] {a,b,c,d};
But then the following does not:
int[] t = (int[]) o;
Surprisingly you get the same problem with String:
String sa = "a";
String sb = "b";
String sc = "c";
String sd = "d";
Object[] so = new Object[] {sa,sb,sc,sd};
String[] st = (String[]) so;
Yields a class cast exception on the last line. Still this works:
Object[] sy = (Object[])new String[]{sa,sb,sc,sd};
String[] sz = (String[]) sy;

A int[] is an array of primitives but also an Object itself. It is not an array of Objects
There is no auto-boxing support for arrays. You need to pick the right type of array to start with and not be converting it at runtime.

Any array, including int[] is actually an Object. This is why you can cast to Object. However, int is a primitive, so it doesn't extend Object, so you cannot cast to Object[].

As you say: String inheriting from Object and int not inheriting from Object, that's the reason. int, boolean, double... are primitive types and they don't extend from Object. You should use Integer instead of int.
Integer[] t;
Object[] z = (Object[]) t;

An object is a class instance or an array.
It is stated in The JLS section 4.3.1.
Now, int[] is an array, which is an Object.
String[] s;
and
int[]
differ in following way:
Former can point to an array of String objects, but latter can point to an array of primitive int.

I just found the answer I was looking for myself. The reason why you cannot cast int[] to Object[] is not because int is a primitive and does not extend Object, but because int[] itself does not extend Object[]. In code:
int[] t = new int[0];
Object ot = t;
System.out.println(ot instanceof Object[]);
// --> prints 'false'
String[] s = new String[0];
Object os = s;
System.out.println(os instanceof Object[]);
// --> prints 'true'
Edit: the boxing is necessary because Eclipse knows that int[] and Object[] are incompatible.
Edit II: Btw this if(obj instanceof Object[]) allows to check wether a boxed array is an array of a primitive type.

According to Java Spec 4.10.3 Subtyping among Array Types:
If S and T are both reference types, then S[] >1 T[] iff S >1 T.
Object >1 Object[]
If P is a primitive type, then Object >1 P[]
S >1 T means that T is a direct subtype of S
It basically means, that int[] and Integer[] are in different branches of type hierarchy in Java and can't be cast one to another.

Related

Accessing integers from an object of class Object

In the code below an integer array is assigned to an object. If that's possible, why can't i access them through obj? The code compiles, but i get a ClassCastException, I have tried casting the object to String, i get the same error
public class test
{ public static void main(String ab[])
{
Object obj = new int[] {1,2,3,4,5,6,7,8,9,10};
Integer[] i = (Integer[]) obj;
for( Integer c : i)
System.out.println(c);
}
}
An int[] is not the same as an Integer[].
You create an int[]:
Object obj = new int[] {1,2,3,4,5,6,7,8,9,10};
But then you attempt to cast it back to an Integer[], which you cannot do, because it is an int[]. int[] and Integer[] are both Object, but you cannot cast between the two like that, for the same reason that, e.g., this does not work:
Object obj = new String("");
File f = (File)obj; // obj is a String, will throw ClassCastException
Instead, either create an Integer[] to begin with:
Object obj = new Integer[] {1,2,3,4,5,6,7,8,9,10};
Integer[] i = (Integer[]) obj;
Or use an int[]:
Object obj = new int[] {1,2,3,4,5,6,7,8,9,10};
int[] i = (int[]) obj;
The same is true of your attempt to cast an int[] to a String. You can't convert things just by casting them around in Java.
It is because you are trying to cast an object of type int[] to an object of type Integer[], that is not possible, although an Integer class can hold int types and in later versions of java you can even assign an int to an Integer like this:
Integer a = 2;
they are different.
If you are using java 5 or above you can do something like this:
public class test
{ public static void main(String ab[])
{
Object obj = new Integer[] {1,2,3,4,5,6,7,8,9,10};
Integer[] i = (Integer[]) obj;
for( Integer c : i)
System.out.println(c);
}
}

Java Object class MYSTERY

While Porting a Game I come to a below statement
Object o = new Object[]{"A","B"};
It's really weird!
But when I try the same with "String" then compiler report me an Error msg
String s = new String[] {"A", "B", "C"}; Error: Type mismatch:
cannot convert from String[] to String
Can you please reveal the Mystery of it ?
You have a trivial error in your code. The fact that every class extends Object makes the error more difficult to find.
Since every class (including arrays) extends Object, conversion from A[] to Object is possible.
You wrote int i = new int[] but that's a mistake, you should have written int[] i.
Probably. Object a = new Object[] is not what you wanted to do.
In Java, Array is an Object too. So you can do
Object o = new Object[]{"A","B"};
or
Object o = new String[]{"A","B"};// But array of String not a String
or
Object o = new int[]{1,2};// But array of int not an int
An "Array" of objects is also an object. But an "Array" of ints is NOT an int.
i.e, an int reference cannot point to an Array but an object reference can.
Object[] obj = new Object[5];// works fine
An object can be anything. It can be an array, it can be an single variable.
Object O = new Object[]{"S","A"};
When you define object you can type cast it to your desired data type.
You can not assign an array of a data type to a single variable of that 'same' datatype.
Every array is an Object[] AND an Object, that's why the following are equally valid:
Object[] o = new Object[]{"A","B"};
Object o = new Object[]{"A","B"};
However a String[] is not a String (and vice-versa) and a int[] is not a int (and vice-versa).
Indeed, you would blend primitives with objects in this latter case.

Assign Object array with Integer elements to Integer array

I searched the internet but didn't found any appropriate solution.
In my application I've got an array of integers. I need to access (assign to) the array via reflection. The application creates an object array that contains Integer elements. Java doesn't allow to assign this Object array to the Integer array.
Is it not possible in Java? My application only knows the Class Object of the Integer array field. The code is dynamically. The type may be an arbitrary type.
private final Integer[] destArray = new Integer[2];
public static void main(final String[] args) throws Exception {
final ReloadDifferentObjectsTest o = new ReloadDifferentObjectsTest();
final Object[] srcArray = {Integer.valueOf(1), Integer.valueOf(2)};
final Field f = o.getClass().getDeclaredField("destArray");
f.setAccessible(true);
// first trial
// f.set(o, srcArray);
// second trial
// Object tmpArray = Array.newInstance(f.getType().getComponentType(), srcArray.length);
// tmpArray = Arrays.copyOfRange(srcArray, 0, srcArray.length);
// f.set(o, tmpArray);
// third trial
Object tmpArray = Array.newInstance(f.getType().getComponentType(), srcArray.length);
tmpArray = f.getType().getComponentType().cast(Arrays.copyOfRange(srcArray, 0, srcArray.length));
f.set(o, tmpArray);
}
No, you can't cast a value which is actually a reference to an instance of Object[] to an Integer[] variable - and that's a good thing. Imagine if that were valid... consider:
Object[] values = { new Integer(5), new Integer(10) };
Integer[] integers = values;
Integer x = integers[0]; // Okay so far
values[0] = new Object(); // Sneaky!
Integer y = integers[0]; // ??? This would have to fail!
If you want to cast something to Integer[], it has to actually be an Integer[]. So this line:
final Object[] srcArray = {Integer.valueOf(1), Integer.valueOf(2)};
... needs to change to create an instance of Integer[].
Yes, the type of a Java array is covariantly linked to its element type. Specifically, Object[] is a supertype of Integer[] and as such is not assignment-compatible with it. You must create an Integer[] at the outset to be able to assign it to an Integer[]-typed variable. From your posted code I can see no reason why you would not do that.
Ok, found the solution... I've got to set each single element via reflection:
// fourth trial
final Object tmpArray = Array.newInstance(f.getType().getComponentType(), srcArray.length);
for (int i = 0; i < srcArray.length; i++) {
Array.set(tmpArray, i, srcArray[i]);
}
f.set(o, tmpArray);

Why does Collection<E>#toArray() not return E[]?

Why does Collection<E>.toArray() (non-parameterized method) return Object[]?
Is it one of those consciously taken decisions? Is there any reason why the toArray() method would not be able to return a E[], if it wanted to?
It's because an array of type T cannot be instantiated without knowing the type Class<T>. Contrast this with toArray(T[] array), which has the following source (example from LinkedList). Notice that the passed-in array is used not only as a possible container, but to possibly instantiate a new array of that type. This code throws an exception if T is not a superclass of E; if objects can't be added to the array.
#SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
if (a.length > size)
a[size] = null;
return a;
}
Generics in Java are implemented using a technique called type erasure. This means that an instance of a generic class does not have any information about its generic type. Consider this
List<String> list = new ArrayList<String>();
list.toArray();
since list does not know about its generic type it can create only Object[]
Array containers have an associated item data type, preserved at runtime. If you construct an Object array and then add strings, this object won't be castable to String[]:
Object[] objArr = new Object[] {"a", "b"};
String[] strArr = (String[]) objArr; //Produces ClassCastException
You can also notice how this array property is used at runtime when you add items of an incorrect type to an array:
String[] strArr = new String[] {"a", "b"};
Object[] objArr = (Object[]) strArr; //Legal this time
objArr[0] = 15; //Produces ArrayStoreException
Generic type arguments are erased at runtime, so the JVM doesn't know what specific array type to create at runtime when you call toArray().

casting Object array to Integer array error

What's wrong with the following code?
Object[] a = new Object[1];
Integer b=1;
a[0]=b;
Integer[] c = (Integer[]) a;
The code has the following error at the last line :
Exception in thread "main" java.lang.ClassCastException:
[Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
Ross, you can use Arrays.copyof() or Arrays.copyOfRange() too.
Integer[] integerArray = Arrays.copyOf(a, a.length, Integer[].class);
Integer[] integerArray = Arrays.copyOfRange(a, 0, a.length, Integer[].class);
Here the reason to hitting an ClassCastException is you can't treat an array of Integer as an array of Object. Integer[] is a subtype of Object[] but Object[] is not a Integer[].
And the following also will not give an ClassCastException.
Object[] a = new Integer[1];
Integer b=1;
a[0]=b;
Integer[] c = (Integer[]) a;
You can't cast an Object array to an Integer array. You have to loop through all elements of a and cast each one individually.
Object[] a = new Object[1];
Integer b=1;
a[0]=b;
Integer[] c = new Integer[a.length];
for(int i = 0; i < a.length; i++)
{
c[i] = (Integer) a[i];
}
Edit: I believe the rationale behind this restriction is that when casting, the JVM wants to ensure type-safety at runtime. Since an array of Objects can be anything besides Integers, the JVM would have to do what the above code is doing anyway (look at each element individually). The language designers decided they didn't want the JVM to do that (I'm not sure why, but I'm sure it's a good reason).
However, you can cast a subtype array to a supertype array (e.g. Integer[] to Object[])!
Or do the following:
...
Integer[] integerArray = new Integer[integerList.size()];
integerList.toArray(integerArray);
return integerArray;
}
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
you try to cast an Array of Object to cast into Array of Integer. You cant do it. This type of downcast is not permitted.
You can make an array of Integer, and after that copy every value of the first array into second array.
When casting is done in Java, Java compiler as well as Java run-time check whether the casting is possible or not and throws errors in case not.
When casting of Object types is involved, the instanceof test should pass in order for the assignment to go through.
In your example it results
Object[] a = new Object[1];
boolean isIntegerArr = a instanceof Integer[]
If you do a sysout of the above line, it would return false;
So trying an instance of check before casting would help.
So, to fix the error, you can either add 'instanceof' check
OR
use following line of code:
(Arrays.asList(a)).toArray(c);
Please do note that the above code would fail, if the Object array contains any entry that is other than Integer.

Categories

Resources