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);
Related
Is there a way to define a default value for an object in array to be initialized with?
In the same way that primitive types are initialized when declaring an array of them:
int[] myIntArray = new int[5]; // we now have an array of 5 zeroes
char[] myCharArray = new char[2]; // an array in which all members are "\u0000"
etc.
I'd like to declare an array of objects of a type that I've defined, and have them automatically initialize in a similar fashion.
I suppose this would mean I'd like to run new myObject() for each index in the array (with the default constructor).
I haven't been able to find anything relevant online, the closest I got was to use Arrays.fill(myArray, new MyObject()) after initializing the array (which actually just creates one object and fills the array with pointers to it), or just using a loop to go over the array and initialize each cell.
thank you!
EDIT: I realized this is relevant not just to arrays, but for declaring objects in general and having them default to a value / initialize automatically.
The Java 8 way:
MyObject[] arr = Stream.generate(() -> new MyObject())
.limit(5)
.toArray(MyObject[]::new);
This will create an infinite Stream of objects produced by the supplier () -> new MyObject(), limit the stream to the total desired length, and collect it into an array.
If you wanted to set some properties on the object or something, you could have a more involved supplier:
() -> {
MyObject result = new MyObject();
result.setName("foo");
return result;
}
Do this so you can initialize the array when declaring it:
int[] myIntArray = {0, 0, 0,0,0};
char[] myCharArray = { 'x', 'p' };
you could of course do:
int[] myIntArray = new int[5];
and the in a for loop set all indexes to the initial value... but this can take a while if the array is bigger...
Edit:
for custom objects is the same just use an anonymous constructor in the init
Example:
public class SOFPointClass {
private int x;
private int y;
public SOFPointClass(int x, int y) {
this.x = x;
this.y = y;
}
// test
public static void main(String[] args) {
SOFPointClass[] pointsArray = { new SOFPointClass(0,0) , new SOFPointClass(1,1)};
}
}
I don't see a way that Java provides to do this.
My suggestion would be define a function to do it.
Object[] initialize(Class aClass, int number) throws IllegalAccessException, InstantiationException {
Object[] result = new Object[number];
for (int i = 0; i < number; ++i) {
result[i] = aClass.newInstance();
}
}
Then call it as Object[] arr = initialize(YourClass.class, 10)
In Java, the array is initialized with the default value of the type. For example, int default is 0. The default value for cells of an array of objects is null as the array cells only hold references to the memory slot contains the object itself. The default reference points to null. In order to fill it with another default value, you have to call Arrays.fill() as you mentioned.
Object[] arr=new Object[2];
Arrays.fill(arr, new Object());
As far as I know there is no way of doing what you want with just plain java (that is to say there may be an external library I don't know about).
I would take the hit and loop over the array. Something like this should work:
myObject[] array = new myObject[5];
for (int i = 0; i < array.length; i++) {
array[i] = new myObject();
}
You could also shorten this using lambdas, like Cardano mentioned in his answer.
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);
}
}
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 8 years ago.
Beginner Java question: when I have
Integer i = 6;
ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);
then I write i = 8, ar.get(0) returns 6.
But if I trie the same thing with a class of mine:
class MyC
{
Integer i;
}
MyC myc = new MyC();
myc.i = 6;
ArrayList<MyC> ar = ArrayList<MyC>();
ar.add(myc);
then do myc.i = 8, ar.get(0) returns 8.
Can you please explain this behavior?
The problem has nothing to do with autoboxing, as some answers say.
In the first example you create an Integer and put it in the ArrayList.
Then you change the pointer to the Integer, so that i is pointing to another Integer.
This don't affects the Integer of the ArrayList.
In the second example you create an object and put it in the ArrayList.
Then you change the state of this object by myc.i = 8.
This way the object in the ArrayList is changed.
This is because i = 8 is turned by the compiler into i = new Integer(8), since i is of Integer type, not int, so you have 2 references now. In your second example, there's still one reference referenced from both myc and first element of ar.
As pointed out by Sotirios in comment, if i was primitive, you'll get the same result. But because of slightly different reason:
int i = 6;
ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);
i = 8; // changes not a ref, but value on stack
System.out.println(ar.get(0)); // prints out 6
Here you have not two references, but one (to autoboxed Integer inside ar).
All variables, with the exception of primitive types, store references, not values.
First example
Integer i = 6;
Create a new Integer object (lets call it I1) and store a reference to it in i
ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);`
Create an ArrayList, and store a reference to I1 in it
i = 8;
Create a new (different) Integer object (lets call it I2) and store a reference to it in i
So now, i = I2, and ar.get(0) = I1
Second example
MyC myc = new MyC();
Create a new MyC (let's call it C) and store a reference to in in myc
myc.i = 6;
Create a new Integer object (lets call it I1) and store a reference to it in C.i
ArrayList<MyC> ar = ArrayList<MyC>();
ar.add(myc);
Create an ArrayList, and store a reference to C in it.
myc.i = 8
Create a new Integer object (lets call it I2) and store a reference to it in C.i
So now myc = C, myc.i = I2, ar.get(0) = C, and therefore ar.get(0).i = I2.
Nothing is referencing I1 and it will be garbage collected.
Integer is an Object-wrapper around the primitive type of int.
In order to store them in a Collection for example List<Integer> list = new ArrayList<Integer>(), the stored element type needs to be a subclass of Object. Therefore, they are stored by reference, as all Objects are stored as references (and all methods receive references by value, see Parameter passing in Java )
It is important to note that in the case of
List<Integer> list = new ArrayList<Integer>();
list.add(5);
int number = list.get(0);
System.out.println("" + number);
The reason why 5 can be used to add the number is because of auto-boxing. When you get the number from the list, it also implicitly calls .intValue() and returns the value of the wrapper as a primitive int. Then in the println() function, the number is implicitly boxed to Integer and then toString() is called.
Pointing i to a different object does not mutate the (original) object. This is not special to primitives. Say you have a List<List<Object>> or a List<List<String>>:
List<List<String>> wrapper = new ArrayList<List<String>>();
List<String> l1 = new ArrayList<String>();
wrapper.add(l1);
l1 = new ArrayList<String>();
l1.add("hello");
for(List<String> list : wrapper)
{
for(String string : list)
{
System.out.println(string);
}
}
If you now iterate over wrapper you find it contains 1 empty list. This is equivalent to your first example. Your second example looks like:
List<List<String>> wrapper = new ArrayList<List<String>>();
List<String> l1 = new ArrayList<String>();
wrapper.add(l1);
l1.add("hello");
for(List<String> list : wrapper)
{
for(String string : list)
{
System.out.println(string);
}
}
In this case the wrapper now contains 1 list with one value in it.
All variables in Java are references that refer to objects that live out on the heap.
The wrapper classes (e.g. Integer) are special cases. Those implement the Flyweight pattern and are immutable.
I am getting the following error when executing the code below...
I am trying to convert the list of Object arrays to a BigDecimal array using the toArray()
method of the List collection..
When I simply give fileFormatObj.toArray() it is working fine, but when I give like in the code below I am getting the error....
public static void main(String[] args)
{
List<BigDecimal> objList = new ArrayList<BigDecimal>();
List<Object[]> fileFormatObj = new ArrayList<Object[]>();
final Object[] array1 = new Object[1];
array1[0] = new BigDecimal(BigInteger.ONE);
fileFormatObj.add(array1);
if (fileFormatObj != null)
{
//Error here java.lang.System.arraycopy
final BigDecimal[] arr = fileFormatObj
.toArray(new BigDecimal[fileFormatObj.size()]);
objList.addAll(Arrays.asList(arr));
for (final BigDecimal object : arr) {
System.out.println("TEST-->" + object.intValue());
}
}
}
The problem is that the element in fileFormatObj is an Object[], not a BigDecimal. Therefore you can't convert fileFormatObj to a BigDecimal[]. You can't even convert it to a BigDecimal[][] (as an Object[] isn't a BigDecimal[]) but at the moment you're trying to store an array reference in a BigDecimal[]...
It's not clear why you're trying to do it like this, but that's simply not going to work. If you edit your question to explain why you're trying to do this - what the bigger picture is - we can help you more.
If you absolutely have to convert a List<Object[]> to a BigDecimal[] and you want to take the first element of each array, you could use something like:
BigDecimal[] arr = new BigDecimal[fileFormatObj.size()];
for (int i = 0; i < arr.length; i++) {
Object[] fileFormatArray = fileFormatObj.get(i);
Object firstElement = fileFormatArray[0];
arr[i] = (BigDecimal) firstElement;
}
You can do the whole for loop body in a single statement of course - I only split it up here to make it clear exactly where the cast to BigDecimal needs to happen.
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.