Java Object class MYSTERY - java

While Porting a Game I come to a below statement
Object o = new Object[]{"A","B"};
It's really weird!
But when I try the same with "String" then compiler report me an Error msg
String s = new String[] {"A", "B", "C"}; Error: Type mismatch:
cannot convert from String[] to String
Can you please reveal the Mystery of it ?

You have a trivial error in your code. The fact that every class extends Object makes the error more difficult to find.
Since every class (including arrays) extends Object, conversion from A[] to Object is possible.
You wrote int i = new int[] but that's a mistake, you should have written int[] i.
Probably. Object a = new Object[] is not what you wanted to do.

In Java, Array is an Object too. So you can do
Object o = new Object[]{"A","B"};
or
Object o = new String[]{"A","B"};// But array of String not a String
or
Object o = new int[]{1,2};// But array of int not an int

An "Array" of objects is also an object. But an "Array" of ints is NOT an int.
i.e, an int reference cannot point to an Array but an object reference can.
Object[] obj = new Object[5];// works fine

An object can be anything. It can be an array, it can be an single variable.
Object O = new Object[]{"S","A"};
When you define object you can type cast it to your desired data type.
You can not assign an array of a data type to a single variable of that 'same' datatype.

Every array is an Object[] AND an Object, that's why the following are equally valid:
Object[] o = new Object[]{"A","B"};
Object o = new Object[]{"A","B"};
However a String[] is not a String (and vice-versa) and a int[] is not a int (and vice-versa).
Indeed, you would blend primitives with objects in this latter case.

Related

How is String arr = new String[] not possible in Java

i have trouble understand reference types in Java. So in C++ if we wanna allocate some 1D array dynamicly or single object all we do is:
int *a = new int();
int *a = new int[];
But in Java pointers are not avaliable to programers, references are introduced as some type of pointers but without possibilty of arithemtic operation on the value they hold(point?).
As far as i know every non-primitive data type in Java is of type reference :
String obj; //reference
obj = new String();
And if wanna allocate it something we gotta allocate it on heap, and the obj will hold the adress of that object on heap. So in C++ it would be like :
String *obj = new String();
But for the array we gotta do :
String[] obj = new String[];
And I dont understand why exactly? If obj is already of reference type(simple *ptr) why cant we just do :
String obj = new String[];
How does this exactly work in Java?
Is String[] obj actualy **ptr in C++ or am i missing something?
The reason why you can't write
String obj = new String[];
is that the left-hand side and right-hand side have different types. That's all there is to it. An array of Strings is not a String. A reference to an array of Strings is not a reference to a String.
Maybe more fundamentally, Java is not C++.

java collections stores values or references? [duplicate]

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.

String array instance assigned to single Object

I came across this Java question:
Which one of the following declaration is false:
a. Object[] myarr1 = new String[3];
b. Object myarr2 = new String[3];
c. String[] myarr3 = new String[3];
d. String myarr3[] = new String[3];
I thought it seems obvious that b is the answer. However, the declaration in b is actually correct upon my checking in Eclipse!
Furthermore, I tried the following:
A. Object[] myarr1 = new String[]{"a1","b1","c1"};
B. Object myarr2 = new String[]{"a2","b2","c2"};
C. String[] myarr3 = new String[]{"a3","b3","c3"};
and printed out the content of each array to study what it actually means by assigning an Object to a String array.
System.out.println(myarr1[0]); //print "a1"
System.out.println(myarr2[0]); //error
System.out.println(myarr3[0]); //print "a3"
System.out.println(myarr1); //print address of myarr1
System.out.println(myarr2); //print address of myarr2
System.out.println(myarr3); //print address of myarr3
It seems myarr1 and myarr3 behave like ordinary String arrays, while myarr2 is different. Debugging to look into the content of myarr2 however showed that the content and structure of myarr2 seems to be the same as myarr1 and myarr3.
Can someone explain to me the significance of this? What are we doing when we use declaration b or B. What is the structure of myarr2 and how do I access its elements or cast it as if it is a String array? I tried (String[])myarr2 but that was an error.
Thanks to all.
They all compile, so they are all correct, as of Java 6.
b. Object myarr2 = new String[3];
This works, because everything you create with the new operator is an object in Java. You could later cast it back to its real type, for example these will work as expected:
Object myarr2 = new String[] { "first", "second" };
String[] real = (String[]) myarr2;
real[1] = "hello";
System.out.println(real[1]); // will output "hello"
System.out.println(((String[])myarr2)[1]); // will output "hello"
d. String myarr3[] = new String[3];
This is valid but discouraged as per this doc:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
The reason your second print statement emits an error is because the compiler does not know what myarr2 actually is, it just knows it's an Object. For example, you could have had:
Object myarr2 = rand() ? new String[3] : new Dog();
i.e. myarr2 could be some other completely unrelated object as well.
Hence, you cannot index myarr2 as an array. Of course, this can be addressed with a cast:
System.out.println(((String[])myarr2)[0]);

JAVA: why Object [] obj = {new Object[1],new Object[2]} and not other classes?

Hi I have seen that Object [] obj = {new Object[1],new Object[2]} is allowed and I am not sure why it is. If I use other classes instead of Object it's generating errors (like Integer, or ArrayList, or even my classes like Grandpa, Dad and Me)?
Since even an Object[] is an object that's why its not throwing any error. But in reality, what you're actually doing is assigning an array to an Object.
Object[][] obj = {new Object[1],new Object[2]}; // proper way
Object[] obj = {new Object[1],new Object[2]}; // this works because Object[] is treated as an Object
That won't work in the case of String or anything else as each element in a String array has to be a String and not a String array.
String[][] obj = {new String[1],new String[2]}; // proper way as its a 2d array where each element in itself is a 1d array.
String[] obj = {new String[1],new String[2]}; // this won't because each element in String array must be a String
String[] obj = {new String("1"),new String("2")}; // this will work as each element is a string
Your signature satisfied the condition, an array of any Objects.
Object [] obj = {new Object[1],new Object[2]}
Because new Object[1] is an Array and That is also an Object, Since every Class extends Object
obj is just an Object array here. Also Array is a Object too So what is the issue. Object is a base class for any class in Java.
Object [] obj = {Element Should be Objects}
So Array is an Object too.
Object [] obj = {Can have any type of Object because every class by default extends Object Class}
X [] obj = { Array of objects of X Class}
Example:
String[] obj = { Array of String Objects}
Granpa[] gandobj = { Array of Granpa Objects}

Why can you cast int[] to Object, but not to Object[]?

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.

Categories

Resources