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[].
Related
If i try to make array of Object class in java, it works fine
Object[] o = new Integer[]{1,2,3};
for(Object x : o)
System.out.print(x);
Output is: 123
I found out that you can also do
Object o = new Integer[]{1,2,3};
It doesn't give compile fail. I want to know that can we iterate through the Integers in reference 'o' ?
Then i tried this
class A{ }
class B extends A{ }
class App{
public static void main(String[] args) throws InterruptedException {
A a = new B[4];
}
}
But her A a = new B[4]; gives CF
Every single Object-type in Java inherits from the Object class.
So, basically: an Integer is an Object, which is why you can do this:
Object[] o = new Integer[]{1,2,3};
On the other hand, Arrays are Objects, too, meaning you can do this:
Object o = new Integer[]{1,2,3};
In the first example, the Integers are the Objects, in your second, the Object o is a reference to the Array of Integers
UPDATE: The reason between your A and B classes, you do have an Exception, is because even though each B is an A, the Array in which you store your B's is not an A.
Java arrays are covariant. Meaning that, You can use a Sub type in place of Type.
So if you have an array of "Type", you can actually fill that array with "SubType"'s. Well, any class in Java is a Subtype of Object. Hence no error in that case.
Object o = new Integer[]{1,2,3};
It doesn't give compile fail.
Again the same things, as Array is also an Object in the end, hence you are free to assign that to an Object.
I want to know that can we iterate through the Integers in reference 'o' ?
By default, Object is not iterable. Where as Array object is.
So before you going to iterate, you have to cast it to type Array.
Update :
But her A a = new B[4]; gives CF
Ofcourse that is not a valid declaration You should write
A[] a = new B[4]; // just to satisfy the compiler. At run time you are not allowed to store A's in it.
But if you are trying to achive the style
Object o = new Integer[]{1,2,3};
No that won't work here and you can only write
Object o = new B[4];
That is because array is a sub type of Object class and not A class.
The reason this is possible is that an array is a subclass of Object. However, by storing the array in o, the program "forgets" the fact that o is holding an array. For that reason, you cannot iterate over o.
The compiler will only allow you to do things that it "knows" you can do to that particular class. Here's an analogy: you want to haul 1 metric ton of sand for a few miles. Would you request a "vehicle," or would you specifically request some kind of truck that you knew would be large enough to haul the sand? If you request a "vehicle of some kind," for all you know they might send you a Prius, which obviously wouldn't do you any good - a Prius can't haul 1 ton of sand. In this case, the compiler would "complain" that there's absolutely no guarantee that you'll be sent a vehicle that has the capacity to do what you want.
Types work that way, too - by default, it's perfectly valid to upcast the array to type Object, since everything in Java is a subtype of Object. But, from the compiler's perspective, there's absolutely guarantee that you can iterate over something of that type, so it won't let you do that.
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[])
In Java, let a custom object o is of type CustomObject. Then CustomObject o2 = o; would make a reference without copying the contents of o to o2. But will this behaviour remain for an array of CustomObjects:
CustomObject[] os = new CustomObject[2];
os[1] = o;
os[2] = o;
Will os[1] and os[2] be references or they will be direct copies of o and thus separate objects?
Well, you actually mean os[0] and os[1] as arrays are 0-based in Java... but yes, they'll be references. Both array elements will refer to the same object.
Importantly, o isn't an object either:
o is a variable: it has a name and a value
The value of o is a reference: it's either null, or it refers to an object
An object has fields, is of a certain execution-time type, etc
The value of an expression (whether it's a simple variable value, the result of a method call or whatever) is never an object in Java - it's always either a reference or a primitive value.
The way the Java Language Specification defines arrays is just as a collection of variables:
An array object contains a number of variables. The number of variables may be zero, in which case the array is said to be empty. The variables contained in an array have no names; instead they are referenced by array access expressions that use non-negative integer index values. These variables are called the components of the array. If an array has n components, we say n is the length of the array; the components of the array are referenced using integer indices from 0 to n - 1, inclusive.
So it's really a bit like doing:
// Creating the pseudo-array
CustomObject o0 = null;
CustomObject o1 = null;
// Populating it
o0 = o;
o1 = o;
As ever, the assignment operator just copies the value of the right hand side to the left hand side. That value is a reference.
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.)
Is there some hidden meaning in this code which I don't see in java? How can it be useful?
int[] a = new int[1];
than just
int a;
because from my point of view it's the same?
int a
defines a primitive int.
int[] a = new int[1];
defines an array that has space to hold 1 int.
They are two very different things. The primitive has no methods/properites on it, but an array has properties on it (length), and methods (specifically its on clone method, and all the methods of Object).
Arrays are a bit of a weird beast. They are defined in the JLS.
In practice, it would make sense to do this when you need to interact with an API that takes an array and operates on the results. It is perfectly valid to pass in a reference to an array with 0, 1, or n properties. There are probably other valid reasons to define an array with 1 element.
I can't think of any use cases where you would want to define an array with one element, just to bypass the array and get the element.
One is on the stack, one is on the heap.
One difference is that you can write a method that changes its int argument by changing arg[0]. This trick is used quite a bit in some of the code I've seen. It allows you to, for instance, return a boolean indicate success or failure and an int value that serves some other purpose. Without that trick, you'd have to return some sort of object containing the two values.
int a;
defines a variable that can hold an int
int[] a;
defines a variable that can hold an array of int
int[] a = new int[1];
does that above but also initializes it by actually creating an array (of size 1 - it can hold 1 int) and defines the variable a to hold that array, but doesn't define what's in the array.
int[] a = new int[1]{1};
does that above but also defines what's in the array: the int 1.
I suppose it does a similar thing, in that space is allocated for 1 int, but the array also defines an array. I suppose you could say these are similar:
int a = 1;
int b = a + 1;
// now b == 2
int[] a = new int[1]{1};
int b = a[0] + 1;
// now b == 2
An array of size one is not the same thing as a single integer.
Even if they carry the same information, they are different types, so you can use them in different contexts.
For example, if you have a function which performs a function on all elements of an array but you want to compute it only on one value, you should pass a int[1], because the function expects an array and wants to know how many values it should process.
All arrays in java are objects. when declaring: int x = 5; you're declaring a primitive type.
When declaring int[] x = new int[]; you're creating an object with type int[].
So int[] is actually a class.