I wrote a function that would take variable arguments as object.
When I passed in an array of ints of size 1 eg {9}, it treated args[0] as and int array[] than an int so the valueOf did not produce 9.
But If passed in and array of 2 or more ints eg {9,11} then it treated args[0] as 9 and args[1] as 11.
Why does it behave differently.
Note it is being written for Android.
protected String[] whereArgs(Object...args) {
String[] argsStrings = new String[args.length];
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof String){
argsStrings[i] = (String)args[i];
} else {
argsStrings[i] = String.valueOf(args[i]);
}
}
return argsStrings;
}
EDIT Just had a look again I was actually passing them differently in the two ints scenario, one by one and not in an array, sorry.
Why doesn't it split the method(Object...args) into an array of objects when I pass in an array of ints, like what happens with method(int...args)
So now to get the string value I have to individually cast the type of array eg. for int[], double[]
if (args[0] instanceof int[]){
argsStrings[0] = String.valueOf(((int[])args[0])[0]);
Is there a way to write it for any type of object as this causes a crash
argsStrings[0] = String.valueOf(((Object[])args[0])[0]);
java.lang.ClassCastException: int[] cannot be cast to java.lang.Object[]
If you want to pass an array and treat each item as a separate item of the 'args' parameter of your method.. you need to cast your array to an Object[]. e.g: If you pass in your array of integers like below it will do what you want.
whereArgs((Object[])(new Integer[]{1, 2}))
The reason for this is when the source is compiled var-arg methods are actually replaced by an array. all places where the method is being called is converted to an array. If you want to pass an array so that each item becomes a separate argument.. then you need to use the correct array type. in your scenario this will be Object[]. This lets the compiler know that it can leave the method call as it is (without putting the arguments inside a new object[])
Related
I need to pass arguments to a java method func(String, String...).
Problem is I have all the strings I need to pass as arguments, but they are in an ArrayList container.
For Example:
for(...some condition...)
{
//the other method returns an ArrayList with different size in each iteration
ArrayList <String> values = someOtherMethod();
func(values) //values is an ArrayList<String>, containing all the arguments
}
I get an error saying that ArrayList<String> can't be converted to String.
The size of values changes, because the someOtherMethod method returns a container with different size each iteration, so I can't pass values[0], values[1], etc as arguments.
I'm guessing the func wants an X amount of String variables, but I don't know how to convert a container to an X amount of variables when the size of the container isn't constant.
The "..." operator accepts arrays, so you could just do the following:
ArrayList <String> values = someOtherMethod();
func(values.toArray(new String[values.size()]);
It's a little bit complex as func requires one String and then an arbitrary number of additional Strings:
List<String> values = someOtherMethod();
if (values.isEmpty()) {
// handle special case
} else{
func(values.get(0), values.subList(1, values.size()).toArray(new String[]));
}
I'm guessing the func wants an X amount of String variables,
I guess you are looking for Varargs.
Change your function signature to accept as
public someReturnType func(String... vargs) { }
Which takes variable length of args as parameter.
And then inside the method ,you can access them like
for (String currentarg: args) {
// do something with currentarg
}
As a side note : Available from version 1.5 only.
Learn more from docs about Varargs
I'm confused on whether I need to do array initialization...
For this code:
private int[][][] rPos = new int[SIZE][SIZE][2];
Can I start using the array right way, like the following line?
getLocationOnScreen(rPos[i][j]); // pass an array of two integers
And, for this code:
View[][] allViews = new View[SIZE][SIZE];
I then have to make another nested loop, and initialize every View by calling their constructors like so:
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
allViews[i][j] = new View(ctor1, ctor2);
}
}
My question is, why didn't I need to do this for an integer array? And also, what did my "new" keyword do, when I typed View[][] allViews = new View[SIZE][SIZE];?
why didn't I need to do this for an integer array?
Whenever you create an array, the array elements are assigned the default value for the component type of that array. For an int, the default value is 0, so for an int[], all the elements will be initialized to 0 by default.
With reference type, however, the default value is null. So, the issue with those arrays are that, you might get potential NullPointerException, when you try to access some property or method in those array elements. Basically, with array of reference, we mean that the array elements are nothing but references to the actual objects. Initially they don't point to any object.
So, to access any property or method, you have to initialize each array elements to some instance, so as to avoid the NPE.
what did my "new" keyword do, when I typed View[][] allViews = new View[SIZE][SIZE];?
It created an array of array, of type View. The dimension being SIZE x SIZE. But since View is not a primitive type, but a reference type. The values are by default null, as already explained.
getLocationOnScreen(rPos[i][j]); // pass an array of two integers
Of course you passed an array of 2 integers. The component type of rPos[i][j] is an int[]. The default value is null for that too. But in this case, it wouldn't be null, as you have given the dimension for all of your inner array too.
If you change your array declaration to:
private int[][][] rPos = new int[SIZE][SIZE][]; // Missing last dimension
then the value of rPos[i][j] will be null.
Why is this type of conversion(array to Object) possible in Java and what does x refer to ?(can I still access the array elements "s1","s2","s3" through x). Where is the array to Object conversion used?
String[] array = {"s1","s2","s3"};
Object x = array;
This is possible because an Array is an Object. When you do this widening conversion, you tell Java "This is an Object and you don't need to know anything else about it." You won't be able to access the array elements anymore , because plain Objects don't support element access. However, you can cast x back to an array, which would let you access its elements again:
String[] array = {"s1","s2","s3"};
Object x = array;
// These will print out the same memory address,
// because they point to the same object in memory
System.out.println(array);
System.out.println(x);
// This doesn't compile, because x is **only** an Object:
//System.out.println(x[0]);
// Cast x to a String[] (or Object[]) to access its elements.
String[] theSameArray = (String[]) x;
System.out.println(theSameArray[0]); // prints s1
System.out.println(((Object[]) x)[0]); // prints s1
This is called a widening reference conversion (JLS Section 5.1.5). x still refers to the array, but Java only knows x as an Object.
You cannot access the array elements directly through x unless you cast it back to String[] first.
Every array type in Java ultimately is a kind of Object. There is no conversion going on here; it's just the usual ability to assign a subtype value to a supertype variable.
The other answers have pointed out that arrays extend Object. To answer your last question:
Where is the array to Object conversion used?
This would rarely be used, but one use case is related to varargs. Consider this method:
static void count(Object... objects) {
System.out.println("There are " + objects.length + " object(s).");
}
In order to treat a single array argument as an element of the varags, you would need to cast to Object:
String[] strings = {"s1", "s2", "s3"};
count(strings); //There are 3 object(s).
count((Object)strings); //There are 1 object(s).
This is because a varargs parameter is an array first and foremost, so when it's ambiguous the compiler treats an array parameter that way. Upcasting to Object tells the compiler otherwise.
in your code x is a pointer to an array of String which names array.
so what ever you change in array would happen to the x too, but it seems to be useless , because Object is a super class for String[] so wherever you should use Object you can use String[].
I'm attempting to create a Java object array and place the array inside itself at its second index (in order to represent a self-similar fractal with the array), but when I try to access theArray[1][1][0], I get this error:
Main.java:11: error: array required, but Object found.
This is what I've tried so far, and I'm not sure why it's not working:
import java.util.*;
import java.lang.*;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
Object[] theArray = new Object[2];
theArray[0] = "This array should contain itself at its second index.";
theArray[1] = theArray; //Now I'm attempting to put the array into itself.
System.out.println(theArray[1][1][0]) //Main.java:11: error: array required, but Object found
}
}
Is it actually possible to put a Java array inside itself, as I'm attempting to do here?
theArray[1] is of compile-time type Object (since it comes from an array of Objects).
You need to cast it to Object[] to use it as an array.
The fundamental problem you're encountering is that although an array that contains itself is a perfectly valid object, it isn't a valid type.
You can nest array types arbitrarily deeply – Object[][][][][][][][][][][][][] is a valid type.
However, the "bottom level" of the type can't be an array.
You're trying to create a type which is an array of itself.
Using generics, that would be possible:
class Evil extends ArrayList<Evil> { }
You're running into a casting error since you've declared theArray to be an Array of Objects. As a result, you can't promise Java that theArray[1] is an Array--it could be any kind of Object. You'll need to break up your access to do what you want:
Object[] innerArray = (Object[]) theArray[1];
System.out.println(innerArray[0] == theArray[0]); // Always true since innerArray IS theArray
while (true) {
// Careful! This loops forever!
// set innerArray = innerArray[1] = theArray = theArray[1] = innerArray...
// all of these are the exact same object (but you have to tell Java their type every time)
innerArray = (Object[]) innerArray[1];
System.out.println(innerArray[0]);
}
Your code is equivalent to
Object arr = theArray[1]; // arr is an Object here, not an array
But you could do
Object[] arr = (Object[] ) theArray[1]; // Now it is an array
This can be done quite easily with ArrayLists:
ArrayList list = new ArrayList();
list.add(list);
So now
System.out.println(list.get(0));
and
System.out.println(((ArrayList)list.get(0)).get(0)); //Casting because .get() returns an Object
Both will output the same thing.
You can take this to an arbitrarily large number of levels, if you want to:
System.out.println(((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)list.get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0));
I understand that for every primitive type in java there is a reference type that can represent the same values, plus null. For example, int and java.lang.Integer.
I also understand that while all arrays (even java.lang.Object[]) derive from java.lang.Object, only arrays of non-primitive types can be converted to java.lang.Object[].
In other words, we can do:
Class type = Integer.class;
Object[] o = (Object[])java.lang.reflect.Array.newInstance(type, 4);
but the following results in an exception:
Class type = int.class;
Object[] o = (Object[])java.lang.reflect.Array.newInstance(type, 4);
so in that particular case we could do:
Class type = int.class;
Object o = java.lang.reflect.Array.newInstance(type, 4);
...which seems fine, until one wonders how to add elements to an Object that represents an array that cannot be converted to Object[].
is the only way around this problem to check the type of the elements of the array and cast the Object as appropriate?
ie:
if (type == int.class)
((int[])o)[0] = getFirstElement();
else if (type == short.class)
((short[])o[0] = getFirstElement();
Besides creating arrays, java.lang.reflect.Array also offers methods to get and set elements in arrays:
Class<?> type = int.class;
Object array = java.lang.reflect.Array.newInstance(type, 4);
int index = 0;
Object value = getFirstElement();
java.lang.reflect.Array.set(array, index, value);
Also note from the documentation that the value is first automatically unwrapped if the array has a primitive component type. So this should work for any array, including those that do not inherit from Object[].
There is a corresponding Object get(Object array, int index) method too.
Well, in the first case you can assign to Object and then use isInstanceOf Object[] to see if you have an array of Object.
But ultimately you have to have some sort of conditional operation to do element access/assignment. Thankfully there are only (IIRC) 7 different scalar data types.
(The language spec could have defined the Integer/Float/et al to include array member access methods -- eg, Integer would define get and set methods for int[]. But they didn't. At best you could define wrappers for the (alas, final) Number subclasses to define these methods.)