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.
Related
Why first line of following method compiles while second not? I would expect both fail.
import java.io.Serializable;
public class ArrayConversions {
Serializable serial = new Serializable[5];
Runnable run = new Runnable[5];
}
The first line compiles because all arrays implement Serializable. From the JLS section 10.8:
Although an array type is not a class, the Class object of every array acts as if:
The direct superclass of every array type is Object.
Every array type implements the interfaces Cloneable and java.io.Serializable.
So you could use:
Serializable serial = new int[10];
You happen to have created a Serializable[], but that's just a coincidence - it's not like you're meant to be able to assign an array type value to its element type value.
So your mistake can be seen for Object as well:
Object o = new Object[10]; // Or new String[10] or new int[10] or whatever
... but these are just about what array types support.
array is Serializable that why its fine to say
Serializable serial = new Serializable[5];
The second one should be obvious. We would expect Runnable[] run.... The first one is not that obvious. It is because an array of Serializable does implement the Serializable interface - in a hidden way. So an array can be considered as a Serializable object.
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 think this is impossible but let's try:
Is it possible to write the routine analyzeArrayList()
in such way that it prints dimension of ArrayList
and the bottomtype of list.
The example code should print:
Dimension = 2 and Bottom type = class java.lang.Float
Dimension = 3 and Bottom type = class java.lang.Integer
We suppose that the parameter s is always instance of ArrayList,
not instance of some other type. Note that list may be empty but not null.
void analyzeArrayList(Object s)
{
int dimension;
String typeString;
//<Some code here!>
System.out.println("Dimension = "+dimension+" and Bottom type = "+typeString);
}
Object s = new ArrayList<ArrayList<Float>>();
Object t = new ArrayList<ArrayList<ArrayList<Integer>>>();
.
.
analyzeArrayList(s);
analyzeArrayList(t);
Comment for this:
It is funny that if you have a object with field
ArrayList<ArrayList<Float>>
then you can write the method
void analyzeArrayList(Field s)
if you know that Field s represents ArrayList.
It is not possible due to type erasure.
Java only considers generics at compile time. If you have a List<String> and List<Integer>, the compiler knows that the lists are from different types which make it capable of creating some type of type-safe environment on a per-instance basis. Because of type erasure, at runtime it is like both lists contain objects and are equivalent to each other.
i know how to hard code an algorithm on how to check the types of each object in an arraylist, but is there any other way in checking the type of that ArrayList<> in one go, i mean my application has only three types of arraylist. Say i have a function that returns an ArrayList, and its definiton is that in a variable o (its an arraylist of object ofcourse) i'll add a person object,
o.add(person);
and having added all person data on an arraylist of objects and when a call this function say the name of my function is getData(),
ArrayList <Object> obj = getData();
so i know that in that ArrayList that i returned from calling getData() that it is all person object, how do i know the type of that ArrayList?.
Just wanted that function to be more generic in sense, this is for my application though, geniric troughout my application.
Is there any other way of doing this, i can think of an algorithm but is there any short cut or easy way of doing this?..
There is no such thing as 'the type' of an ArrayList.
The class ArrayList stores a list of Object references. It doesn't know and doesn't care if they are all of some type.
The Java generic system adds compile-time checking to help you keep track of types. So, if you declare ArrayList<Person>, you will get compile errors if you write code that could insert a non-Person into your list.
At runtime, the only way to tell what is in an ArrayList to iterate over all the contained items and check them with instanceof.
Actually there is a way without casting every item manually(it still is ugly though..)
//start with an arraylist of unknown generic type
ArrayList <Object> obj = getData();
//Make an array from it(basically the same as looping over the list
// and casting it to the real type of the list entries)
Object[] objArr = obj.toArray();
//Check if the array is not empty and if the componentType of the
//array can hold an instance of the class Person
if(objArr.length>0
&& objArr.getClass().getComponentType().isAssignableFrom(Person.class)) {
// do sth....
}
This should not give any unchecked warnings.
You could use it like this:
private boolean isArrayOfType(Object[] array,Class<?> aClass) {
return array.length > 0
&& array.getClass().getComponentType().isAssignableFrom(aClass);
}
Object[] personArr = getData().toArray();
if(isArrayOfType(personArr,Person.class) {
//Do anything...
}
What won't work is the following:
// -> This won't work, sry!
ArrayList<Person> personArrayList = Arrays.asList((Person[])personArr);
If the list is not empty, get the first element:
type = this.list.get(0).getClass().getSimpleName();
Considering this part of a Java class,
private List<Object> components = new ArrayList<Object>();
private A a;
private B b;
private C c;
add(a, b, c);
public void add(Object... component){
for(Object o : component) {
components.add((CAST)o);
}
}
I would like to cast my Object o in the list, by the good type.
The expected result here would be to have A a, B b, C c in my list.
I try with getClass(), but I didn't compile. How can I upcast Objects, considering that I already know the expected Java type?
edit:
I need to add a first object of type A, a second object of type B, a second object of type C, ... (I don't know the number of items to add) if a list so that I will be able to get the list containing N objects correctly typed. (gtt(0) would be typed as A, get(1) as B, and get(2) as C )
Because I don't know the number of objects and that I initially don't know the object's type, I delclared my list as Object.
I created a method (add in that case). It varargs will help me for looping in the collection because I don't know the number of args.
I would simply like to get the first object, the second object and the third object (and so on) in my varargs, and to simply push it in my list, but not as Object type, as A, B or C, depend of what I received!
I don't know if it's more clear.
Your list already accepts Objects
private List<Object> components = new ArrayList<Object>();
why do you need to upcast?
First, you can never upcast in this case. The only place you REALLY need an upcast is when you're accessing a method specific to C, not in B or A; or specific to B not in A. (or neither in Object)
You seem to be misunderstanding how the runtime type of an object works. When you put an 'A' into a List it does not stop being an 'A' and become an Object. If you take it out later and cast it back to an 'A' it is still the original runtime type. There is nothing gained by casting it before putting it in the list.
Consider this
Object str = "FOO";
List<Object> list = new LinkedList<Object>();
list.add(str);
String str1 = (String) list.get(0);
System.out.println(str1.length());
Prints '3'. "FOO" never stopped being a String just because the reference type of the pointer to it was Object.
To be honest, I agree with everyone above, that it doesn't make much sense upcasting in the example you gave. Since you declared that the list will contain Objects, you will have to do the cast again when retrieving the object from the list.
However, there is allways the type comparison operator instanceof which you could use.
public void add(Object... component){
for(Object o : component) {
if(o instanceof CAST)
components.add((CAST)o);
}
}