What is Object[] exactly? - java

I am having difficulty understanding what an Object[] is. Is it an Array that keeps Objects ? For example what happens when we do this :
int a = 5;
String b = "Hi";
Object[] c = { a, b };
Did I just create an object with properties a and b added to it ? Or did I get an Object Array in which a and b was counted as objects and elements of this c the object array ?
Thanks.

Actually you created an array of objects derived from Object (which is true for all object in Java), now containing an Integer (created by autoboxing) on position 0, and a String on position 1.

Java is not dynamically typed so you cannot add properties on the fly like in javascript (without reflection). Btw. in java you dont call them properties, but instance-members/fields or methods if its a function, which are defined in classes (but you usually work with instances which is constructed from a class). So Object is a class and Object obj = new Object(); obj is an instance
The notation ClassName[] always notates an array of type ClassName, so
Object[]
notates an array of objects. And
String[]
an array that can only contain Strings.
You can initialize an array with
Object[] objArr = new Object[3];
which creates a new empty array which can hold 3 elements. Or you can directly set the elements by
Object[] objArr = {"elem1","elem2","elem3"};
which creates an array with 3 elements (elem1-3). So therefore:
System.out.println(objArr[0]); //"elem1"
System.out.println(objArr[1]); //"elem2"
System.out.println(objArr[2]); //"elem3"
System.out.println(objArr[3]); // ArrayIndexOutOfBoundsException
Because you used Objectas a type you can set practically anything to the array since any class automatically inherits from Object
Object[] objArr = {"elem1",2.34,new Date()};
System.out.println(objArr[0]); //"elem1"
System.out.println(objArr[1]); //2.34
System.out.println(objArr[2]); //11.05.2014
2.34 is a double, so a primitive, but since 1.4 java autoboxes every primitive into its Object pendant (so Double), thats why it works. Note that usually in a statically typed language you dont want to do that this way since you lose alle the advantages of statical type checks, so better define your types and use them.

Did I just create an object with properties a and b added to it ?
No. Those are elements. Properties != Elements.
did I get an Object Array in which a and b was counted as objects and elements of this c the object array ?
Little wrong. Counted as elements, which are objects.
Object[] c = { a, b }; // a is Integer and b is String
When you write the above line, that means you created an array Objects with elements a and b in it. You can refer the array with c

Is it an Array that keeps Objects ?
To be precise, it's an Object that contains references to other Objects.
All objects in Java are created and live on the heap until the garbage collector reclaims them. References point to those memory locations and give your program access.
The example you gave uses two immutable objects. The real fun would happen if you chose a mutable object and added it to your array.

On executing the program it will print,
5
Hi
on iterating the array. that shows the Object array consist of a of Integer and b of String.

It's an array of objects. You've auto-boxed a from a primitive int into an Integer and added that, and String b to the Object array. Remember all Objects extend Object. Try casting the Objects to their subclass types and maybe this will help you understand what's going on. E.G.
int a2 = (Integer) c[0];
String b2 = (String) c[1];

Object[] is an array of object references. From your code, imagine you did this:
int a = 5;
String b = "Hi";
Object o1 = a; // Autoboxes to java.lang.Integer
Object o2 = b;
Pretty similar to:
int a = 5;
String b = "Hi";
Object[] c = new Object[2];
c[0] = a;
c[1] = b;
... right? Which is exactly what your code above does, in a more shorthand way. So, you create an array where each element holds a reference to an Object.

Objects are superclasses of every non-primitive in Java. In your code:
int a = 5; // <- int is a primitive
String b = "Hi"; // <- String is a subclass of Object
Object[] c = { a, b };
c wants to have an array of Objects, and since a is an int, autoboxing occurs (this means that the compiler makes the int an Integer-object). You can compare it to the following code (this is basically what the compiler does behind the scenes).
int a = 5; // <- int is a primitive
String b = "Hi"; // <- String is a subclass of Object
Object[] c = { new Integer(a), b }; // <- int is autoboxed to it's container-class Integer
As I mentioned, Objects are the superclass of every non-primive in Java. So let's compare your code to the following:
I have three classes:
class C{ } // Just compare this with Object
class B extends C{ } // Compare this with String
class A extends C{ } // Compare this with Integer
// translating your code to:
A a = new A();
B b = new B();
C[] c = { a, b };
The left side is the reference type and the right side is the object type.
// List is the reference type, ArrayList is the object type
List<String> list = new ArrayList<String>(); // (or List<String> list = new ArrayList<>(); in Java 7+)
// With the C, B and A classes above:
// C is the reference type, A is the object type
C myClass = new A();

Related

Arrays are really homogeneous?

In the below code, EX1 and EX 2 prov the homogeneous theory but in EX3 it holds multiple types values. So then, how we can say arrays are homogeneous? What is the exact theory behind this?
public class Test {
public static void main(String[] args) {
// Ex 1
int [] intArr = new int[5];
intArr[0] = 1;
intArr[1] = 2;
// Ex 2
int [] intArr2 = new int[5];
intArr2[0] = 1;
intArr2[1] = "ss";
// Ex 3
Object [] objArr = new Object[5];
objArr[0] = 1;
objArr[1] = "ss";
objArr[3] = new Object();
}
}
There are a two concepts here: inheritance and auto-boxing
Inheritance -
A String inherits from Object and hence is an Object. This means that String gets all methods and properties defined in the Object class automatically at compile time. It is an Object plus additional stuff that is specific to the String. However, it can be viewed by Java as an Object because it is an Object. When it is added to the array, it is added as an Object, not as a String. That is because the Array is defined as an Array of objects.
char a = "ss".charAt(1); // Legal as charAt(..) is a method in the String class
Object [] objArr = new Object[5];
objArr[1] = "ss";
objArr[1].charAt(1); // Not legal because charAt(..) method is not defined for Object
See Oracle Tutorial.
Auto-Boxing -
Java performs a shortcut known as auto-boxing to a automatically convert primitives to a special set of wrapper Classes all of which inherit from Object. Hence, because of auto-boxing and inheritance, assigning a number to an Object will convert that number to an Object as well.
Hence, everything added to the array was added as an Object. It is true that the objects in the array may be classes that inherited from Object. However, as far as the array is concerned, they are of type Object. Even so, if you were to pull it out of the array and cast it as an Integer, you could do so. It still carries the Integer information with it but that information in not available without a cast. From the array's point of view, it is only an Object.
See Oracle Tutorial.

Is array size irrelevant in java?

As per the below statement,
An array of subclass may be assigned to an array of its superclass. An array of implementing class may be assigned to an array of its interface type. Size is irrelevant.
I wrote below sample code to check the behavior of size in array
interface I{}
class C implements I{}
/* dummy.java*/
public class dummy{
public static void main(String[] args){
C[] c = new C[6];
I[] i = new I[2];
c[0] = new C();
c[1] = new C();
c[2] = new C();
c[3] = new C();
c[4] = new C();
c[5] = new C();
i = c;
System.out.println(i[5].getClass());
}
}
When i say, new C[6];, an object [null,null,null,null,null,null] gets created of type class [LC and c points to this object. When i say, new I[2];, an object [null,null] gets created of type class [LI and i points to this object.
My question:
How interface array is working here, when i say i[5], despite an object [null, null] being created after defining new I[2]? What exactly is happening when i say i = c;? Is size of array of interface new I[2]; getting modified during assignment i = c;?
What that quote is trying to say is that the size of an array is part of the object, ie. it is not part of the reference or the variable type.
In
i = c;
you are assigning a copy of the value of the reference held in c to i. That is, i will reference the same instance as c.
Is size of array of interface new I[2]; getting modified during assignment i=c;?
No, that's the whole point. i and c are just variables. Variable assignment has no side effects.
When you set
i=c
You are setting i to point to the object created by c. Therefore, i will now point to C[6]; < this array
So...
i[1] = new I();
c[1] will return a I object

ArrayStoreException when trying to set an element of an array to a superclass object

class A {}
class B extends A {}
Hi, I'm learning Java and I'm trying to understand why this works:
A[] tab = new A[10];
tab[0] = new B();
and not this:
A[] tab = new B[10];
tab[0] = new A();
this line A[] tab = new B[10]; means that the compiler is booking 10 places for B in memory. tab[0] = new A() is setting tab[0] equal to a new A object that is smaller (?) than B (B extends A).
Why is there an ArrayStoreException: A error ? How does it work ?
You can store subclasses of an object, inside that object. ie B can be stored in A, but A is a superclass of type B. Basically, any class below class X in the inheritance chain can be referred to as type X, but any class above class X in the inheritance chain can NOT be referred to as type X.
Your example
A[] tab = new A[10]; // Perfectly fine. Equal objects.
tab[0] = new B(); // B is a subclass of A, so this is allowed.
A[] tab = new B[10]; // Same principle as above, B is a subclass of A
tab[0] = new A(); // A is a SUPERCLASS of B, so it can not be referred to as A
In short, X can only be referred to as Y, if X is a subclass of Y. (Or a subclass of a subclass. It's a recursive definition).
Let's use some English terms
Instead of A and B, let's have Item and Book.
public class Item {}
public class Book extends Item {}
Now, it makes sense to say:
Item b = new Book(); // All Books are items.
It does not make sense to say:
Book b = new Item(); // All items are definitely not books.
According to Documentation
Thrown to indicate that an attempt has been made to store the wrong
type of object into an array of objects. For example, the following
code generates an ArrayStoreException:
Object x[] = new String[3];
x[0] = new Integer(0);
"My Animal array will contain only Butterflies (A[] tab = new B[10];). Add a new Animal in the array (tab[0] = new A();)."
How to be sure the inserted Animal is a Butterfly?
Because if B extends A, B has ALL of the A characteristics (attributes, methods, etc), PLUS his own.
Then each B is also an A, while an A (that would lack the characteristics of B) is NOT a B.
This boils down to the most essential property of a hierarchical type system, which is the Liskov Substitution Principle: wherever an instance of A is allowed, an instance of any of its subtypes is also allowed. Arrays are no special case.
The thumb rule in java is superclass reference variable can point to sub class object and not vice versa, if you think about it , it makes sense that parent class can point to child class object. List list = new ArrayList()
Given:
class A { }
class B extends A { }
We have:
A [] a = new A [10]; // can store A or B objects
A [] b = new B [10]; // can only store B objects

Initialize object A in java equal to another object B [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I copy an object in Java?
How can I initialize an object (say A) in java and set its initial member values equal to a second object (say B). After initialization I want to modify the members of A without modifying the members of B. So at initialization of A I only want to copy the data of B. How is this done in a nice way??
You could implement and use clone
MyClass b = new MyClass();
MyClass a = b.clone();
Note: some classes are not Cloneable, or have broken implementations. e.g. only have a shallow copy when they should be a deep copy.
If the class is Serializable you can serialize it and deserialize it in memory. Not exactly nice but it works.
Or you could create your own "copy" constructor.
One possible solution for that would be implement clone method on your class and use clone as follows:
MyClass a = new MyClass();
MyClass b = a;
You will notice that clone() isn't really a public method, so your will need to expose it. Additionally you need to tell Java that your object is Cloneable (this is done making your class implement Cloneable). The following code ilustrate it:
public class MyClass implements Cloneable {
#Override
protected MyClass clone() throws CloneNotSupportedException {
return (MyClass)super.clone();
}
}
That all depends on the type of the members. I'll give an Example:
class A
{
public float value;
public int[] anArray;
public A(B b)
{
//primitive may be assigned directly.
this.value = b.value;
// other types different approaches:
//copy the contents of the array
this.anArray = new int[b.anArray.length];
System.arraycopy(b.anArray, 0, this.anArray, 0, b.anArray.length);
}
}
class B
{
float value;
int[] anArray;
public B(int size)
{
this.value = 3f;
this.anArray = new int[size];
for (int i = size - 1; i >= 0; i--)
{
this.anArray[i] = i * 10;
}
}
}
B b = new B(5);
A a = new A(b);
Cloning is a straightforward option for copying. If you ever want to do something where you need more control, create your own method that performs your copy exactly how you need it:
public MyType copy()
{
MyType a = new MyType();
// Initialize how you need to here, use the object this was called from if you'd like
a.property = this.property;
// etc.
return a;
}
This gives you more direct control, but takes more time to code. If clone will suit your purposes, stick to that.
EDIT: I am going to give an example based on your comments on this answer.
Let us assume we have the following types:
TypeA: has the following member variables
int number = 5; // Default value built in by constructor.
int letter = 'x'; // Value is 'a' when constructed but has been changed.
ArrayList<TypeB> list = {b1, b2, b3} // All are initialized.
TypeB: has the following member variables
double decimal = 5.32
TypeC someObject = ...
TypeC: has some stuff, but we are going to ignore it.
Now, When we want to copy TypeA, we must do the following:
Copy over the number and character directly as they are value types.
Copy over a reference to the ArrayList which contains a reference to some TypeBs.
Luckily those are easy steps.
int copyNumber = this.number;
char copyChar = this.letter;
ArrayList<TypeB> copyList = this.list;
return new TypeA(copyNumber, copyChar, copyList);
Now that assumes a particular constructor that takes those three arguments, but hopefully you get the idea.
It would get tricky if you wanted to just get values, not references to all of the TypeBs in the ArrayList. You would have to loop through the ArrayList and create new TypeBs that copied all of ITS values (double and TypeC objects as either references or values...)
In short, what you want is an easier copy to perform. Simple assignment operators copy values with primitive types and references with Objects.

Java Array declaration like { A[] aa = new B[10]}

Today I've written simple test about syntax of declaring array, so, there are 3 classes:
public class A {
}
public class B extends A {
}
public class C extends A {
}
and I've tried to create array using next syntax
A[] aa = new B[10];
So, It is possible, but we can added just instances of class B to this array , If you will try to add instances of A or C you receive java.lang.ArrayStoreException and question, Why can we create array using syntax like that and where is it can be used and make some profit ?
Thanks.
The array holds type Bs. Even though the reference aa could hold arrays of type A[], B[] or C[], (since C and B both extend A), at runtime, the array can only hold things which are Bs.
Class A is not a B. Class C is not a B. Hence the runtime exception.
EDIT:
There are many potential uses for code like this. For example, You can declare an array like this because you might not know until runtime the more explicit type you are working with.
For instance:
Animal[] animals;
if (useDogs) {
animals = new Dog[num];
} else {
animals = new Cat[num];
}
loadIntoCar(animals);
The reason this syntax is allowed in the language is that sometimes you don't care what subclass of objects are in the array. The Java Language Specification rules for array subtyping include:
If S and T are both reference types, then S[] >1 T[] iff S >1 T.
(where >1 means "direct subtype").
This allows one to write a method like this:
public void printArray(Object[] array) {
System.out.print('[');
boolean first = true;
for (Object obj : array) {
if (!first) {
System.out.print(", ");
} else {
first = false;
}
System.out.print(String.valueOf(obj));
}
System.out.print(']');
}
and then call it with:
String[] foo = { "a", "b", "c" };
printArray(foo);
This language feature does have the unfortunate effect of deferring ArrayStoreException problems to run time.
Arrays types are covariant, which means you can declare A[] a = new B[] (Collections, on the contrary, are not : you cannot declare List<A> a = new List<B>()).
This is why the compiler cannot preemptively check that you will only put elements of a valid type in the array, which explains why the check happens only at runtime, when you try to insert an element into the array.
If you want examples, take a look at Arrays. If Java didn't allow arrays polymorphism, we couldn't have functionalities such as sort(Object[] a), toString(Object[] a), binarySearch(Object[] a, Object key), etc. Remember that Band C are subtypes of Object, so you can use that functionality for all of them. Take note that arrays predate generics (Java 1.5.0) and that even generics have it's flaws (the trade-off for Java is that you can't know the generic type at runtime because of type-erasure).

Categories