Array of object references - java

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.

Related

Making an Integer array inside Object class reference variable

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.

Widening conversion from array to Object (java)

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[].

is there a universal way to work with arrays of primitives and arrays of non-primitives in java?

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

When you make a reference = another reference and both values are null?

public static void main(String[] args) {
ArrayList a=null, b=null;
a=b;
a=new ArrayList();
System.out.println(a+""+b);
}
Why in the world b is printed as null ?
I thought java makes references the same then whatever you change in one of them reflects the other. But not in this case !!!
This line:
a = b;
Sets the value of a to the current value of b. That's all it does. The current value of b is null, so it's equivalent to:
a = null;
It does not associate the two variables. It just copies the value of one to another.
Changing the value of a afterwards does not change b at all. The two variables are entirely separate. Note that this is exactly the same for primitive types:
int a = 10;
int b = a;
a = 5;
System.out.println(b); // Prints 10, not 5
Even if you had:
ArrayList<String> a = new ArrayList<String>();
ArragList<String> b = a;
a.add("Hello");
System.out.println(b.get(0)); // Prints "Hello"
That's still not really showing a relationship between the variables a and b. They have the same value, so they refer to the same object (the ArrayList itself) - changes to that object can be observed via either variable. But changing the value of each variable to refer to a different list (or null) won't affect either the other variable or the object itself.
One thing which may be confusing you is what the value of a or b actually is. The value of a variable (or any other expression) in Java is never an object - it's always either a reference or a primitive value.
So an assignment operator, or passing an argument to a method, or anything like that will never copy the object - it will only ever copy the value of the expression (a reference or a primitive value).
Once you understand this, Java starts to make a lot more sense...
Variables like your a and b are called references. They refer to objects. The objects are floating around somewhere else (they are not stored "inside" the variables). When you say a=b you make a refer to whatever b refers to. In your case that makes no difference, because both already refer to null (i.e. to no object at all).
When you assign a new object to a that makes no difference to what b refers to.
Because you've redefined a. When you say:
a=new ArrayList();
You break the existing relationship between a and b.
Simply put. The variables refers to the object the other variable refers to in the moment it is set and not to the variable itself.
ArrayList a=null, b=null; // Both *a* and *b* refers to null
a=b; // Set *a* to refer to what *b* refers to (in this case null)
a=new ArrayList(); // Set *a* to refer to a new arraylist. *b* still refers to null.

Arrays in Java and how they are stored in memory

I'm trying to understand the array setup in java. Why must you initialize space for each each object in the array, after you have created the array. How is it stored in memory like this:
[object][object]
or like this:
[*class]->[object]
[*class]->[object]
In other words, what is actually being done in memory. Does array[0] = new class() just return a reference to a reserved location in memory, and the class[] array = new class[10] statement create something along the lines of 10 pointers, which are later assigned to by the new statements?
Arrays in Java store one of two things: either primitive values (int, char, ...) or references (a.k.a pointers).
So, new Integer[10] creates space for 10 Integer references only. It does not create 10 Integer objects (or even free space for 10 Integer objects).
Incidentally that's exactly the same way that fields, variables and method/constructor parameters work: they too only store primitive values or references.
If you are familiar with C/C++ you can think of Java object references as pointers to objects (or pointers to structs). So:
Person p = new Person();
p.setName("Helios");
is:
declare a p pointer to a Person struct (in the stack)
reserve memory for and initialize Person struct
assign its address to p
execute method setName on object referenced by p
So when you are doing:
Person[] ps = new Person[5];
you are reserving an array of 5 references to Person. Next you will have to create each real person and assign each reference to a place in the array.
Edit: the (almost) C/C++ version of the previous code
class Person { ... };
typedef PersonStruct* Person; // I don't remember if this declaration is ok
Person p = new PersonStruct();
p -> setName(...);
Person[] ps = new Person[5];
// ps is a variable in the stack pointing to the array in the heap
// (being the array five references to the PersoStruct)
and you could do
ps[3] = p;
Arrays are continuous space of memory, so they look like more your first sketch:
[object-reference][object-reference]
array[0] = new class() will store in array[0] a reference to the new created object.
class[] array = new class[10] will create an array of ten empty slots (or ten null references).

Categories