Accessing integers from an object of class Object - java

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);
}
}

Related

How to populate generic array to main

I've got a generic array class and I want to return an array in the main so I can use the sort method that I have ready in the main. I understand that the constructor has an array in it so I'm wondering if I can use that. Or do I need to set up a new method to return this.array ? Also it returns a generic array, how do I choose the type in main?
public class dynamicArray <T>{
private int index;
private T[] array;
public dynamicArray() {
array = (T[])new Object[10];
this.index = 0;
}
public T [] populate() {
return this.array;
}
Here I chose the integer type for the class. I'm not sure how can I extract the
array from the constructor.
public static void main(String[] args) {
dynamicArray<Integer>array = new<Integer>dynamicArray();
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
int [] arr = array.populate();
mergeSort(arr);
System.out.println(array.toString());
}
Unfortunately, arrays and generics don't work well together. Take a look at the source code of java's ArrayList - it is implemented with an Object[] and not a T[] - then every method will cast to T (which costs literally zero, it's just ugly and causes compiler warnings). I advise you do the same here: Arrays actually KNOW their component type (unlike a list of Ts, which does not, there is no method on a java.util.List that you can invoke to get the component type), and therefore casting Object[] to T[] is just wrong; java allows this solely for backwards compatibility reasons.
Basically, you can't work with T[] without things being subtly wrong and a lot of compiler errors.
In this specific case? I would strenuously advise you to use a private List<T> array; field instead of a T[] field.
Your call to array.populate() (that seems like a bizarre name for this method!) IS retrieving the array you created in the constructor. You are doing what you're asking for: "Extracting the array from the constructor" - invoking populate() on the object returned by the new dynamicArray<Integer>() is doing exactly that.
NB: You have a typo in your source code. it's new dynamicArray<Integer>();, not new<Integer>dynamicArray();. Perhaps that's causing some issues?
NB2: Java conventions dictate it's DynamicArray, and something like getBackingArray (instead of populate).
I think you ask two question :
How to set Integer type of that array object.
How to get Integer[] to int[]
Here is the code :
private int index;
private T[] array;
public dynamicArray() {
array = (T[])new Object[10];
this.index = 0;
}
public T [] populate() {
return this.array;
}
public void add(T x) {
array[++index] = x;
}
public static void main(String[] args) {
dynamicArray<Integer>array = new<Integer>dynamicArray();
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
int[] arr = Arrays.stream(array.populate())
.mapToInt(i -> i)
.toArray();
System.out.println(array.toString());
}
Answer for 1st question is you can not set Integer type because there wasn't any add method in your class. Answer for 2nd question is you try to convert Integer[] to int[] but there is no direct way to cast this. you just need to change Integer -> Object then Object -> int. This can be done easily using streams which is in Java 8 and i have used lambda here for showing power of lambda function.
Here is a possible alternative. Pass the type of array to the constructor. But essentially you are creating a limited form of ArrayList so you may just as well use that. Note that this still has the limitation that you can't use primitive arrays as the array type.
dynamicArray<Integer> array = new dynamicArray<>(new Integer[0]);
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
Integer[] a = array.getArray();
System.out.println(Arrays.toString(a));
}
class dynamicArray<T> {
private int size = 0;
private T[] array;
public dynamicArray(T[] a) {
array = a;
}
public void add(T value) {
if (array.length == size) {
array = Arrays.copyOf(array, size == 0 ? 10 : size*2);
}
array[size++] = value;
}
#SuppressWarnings("unchecked")
public T[] getArray() {
// need to copy the array since the length and size could be different.
T[] arrayCopy = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
System.arraycopy(array, 0, arrayCopy, 0, size);
return arrayCopy;
}
}

Why can't a HashSet or LinkedList of Integers converted to int[]?

public static String duplicate(int[] numbers){
Set<Integer> set = new HashSet<>();
Set<Integer> duplicates = new HashSet<>();
for (int num : numbers){
if (set.contains(num)) {
duplicates.add(num);
} else {
set.add(num);
}
}
int[] ans = duplicates.toArray();
return ans.sort().toString();
}
Eclipse says "Type mismatch: cannot convert from Object[] to int[]" for the line int[] ans = duplicates.toArray();
Why not? I tried LinkedList and ArrayList also. The HashSet() uses the type, while does the .toArray() function think the return will be Object[]?
Set.toArray returns Object array
Object[] toArray()
You can convert Set<Integer> to Integer array
Integer[] i = duplicates.toArray(Integer[]::new);
Or you can use java-8 stream by iterating the Set
int[] arr = duplicates.stream().mapToInt(i->i).toArray(); // or mapToInt(Integer::intValue)
Note : On other side your method return type is String and arr.toString() returns string representation of an object like [I#edf4efb here
Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read
int[] is a primitive data type in Java and it's an object and not a Class.
If you need to convert to an Object[] Class you can use the Wrapper classes which is Integer[] since they inherit from Object class.
More about wrapper classes in Java : https://www.geeksforgeeks.org/wrapper-classes-java/

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);

How to create ArrayList (ArrayList<Integer>) from array (int[]) in Java

I have seen the question: Create ArrayList from array
However when I try that solution with following code, it doesn't quite work in all the cases:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class ToArrayList {
public static void main(String[] args) {
// this works
String[] elements = new String[] { "Ryan", "Julie", "Bob" };
List<String> list = new ArrayList<String>(Arrays.asList(elements));
System.out.println(list);
// this works
List<Integer> intList = null;
intList = Arrays.asList(3, 5);
System.out.println(intList);
int[] intArray = new int[] { 0, 1 };
// this doesn't work!
intList = new ArrayList<Integer>(Arrays.asList(intArray));
System.out.println(intList);
}
}
What am I doing wrong here? Shouldn't the code intList = new ArrayList<Integer>(Arrays.asList(intArray)); compile just fine?
The problem in
intList = new ArrayList<Integer>(Arrays.asList(intArray));
is that int[] is considered as a single Object instance since a primitive array extends from Object. This would work if you have Integer[] instead of int[] since now you're sending an array of Object.
Integer[] intArray = new Integer[] { 0, 1 };
//now you're sending a Object array
intList = new ArrayList<Integer>(Arrays.asList(intArray));
From your comment: if you want to still use an int[] (or another primitive type array) as main data, then you need to create an additional array with the wrapper class. For this example:
int[] intArray = new int[] { 0, 1 };
Integer[] integerArray = new Integer[intArray.length];
int i = 0;
for(int intValue : intArray) {
integerArray[i++] = intValue;
}
intList = new ArrayList<Integer>(Arrays.asList(integerArray));
But since you're already using a for loop, I wouldn't mind using a temp wrapper class array, just add your items directly into the list:
int[] intArray = new int[] { 0, 1 };
intList = new ArrayList<Integer>();
for(int intValue : intArray) {
intList.add(intValue);
}
With Java 8 you can do it in one line:
int[] intArr = { 1, 1, 2, 3, 5, 8, 11};
List<Integer> list = Arrays.stream(intArr).boxed().collect(Collectors.toList());
list.forEach(System.out::println);
The issue is about Autoboxing.
Java automatically converts int to Integer automatically. But Java cannot convert int[] to Integer[]. Hence the reason.
public static <T> List<T> asList(T... a)
asList is defined as above. It expects a vararg of type T. i.e. it can take an array of objects of type T. In your case because Java cannot convert int[] to Integer[], hence it takes type T as int[] rather than Integer as desired. Hence you get a list of type List<int[]. You will have to manually convert it into Integer[] from int[].
There is an excellent item in the book Effective Java by Joshua Bloch where he explains the pitfalls of varargs. This is one of them.
It doesn't work because you're using an int[] instead of Integer[]. Try this:
Integer[] intArray = new Integer[] { 0, 1 };
// this should work now
intList = new ArrayList<Integer>(Arrays.asList(intArray));
Collection wants Objects and primitives don't derive from Object. so Integer allow but int is not allow.
So you have to use wrapper class Integer instead of int which is primitive type.
Just example:
Integer[] intArray = new Integer[] { 0, 1 };
intList = new ArrayList<Integer>(Arrays.asList(intArray));

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

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.

Categories

Resources