I have been trying to create my own library to serialize and de-serialize primitive types from a class to xml and from xml to a class instance using reflection to examine method naming patterns and method return types.
So far I have been able to do this with all the basic primitive types but I got stuck on serializing an array of the same primitives.
For example I invoke the class method to get the array of primitives:
method.invoke(clazz, (Object[])null);
This method will return only a primitive array int[], double[], float[], char[] etc. though we don't know which one it will be.
I have tried using a generic such as
T t = (T)method.invoke(clazz, (Object[])null);
T[] t = (T[])method.invoke(clazz, (Object[])null);
But it doesn't let me cast from the primitive array to an object.
And you can't use Array.newInstance assuming we don't know the type.
Is there a way that I can convert this array of primitives to say an Object array in a generic manner.
In a generic manner meaning without needing to know or checking what the type of the array is. Or should I just cycle through all the primitive types and handle all of them separately.
I can do this both ways the only reason I want to do this in a generic manner is to cut down on the redundant code.
Thanks in advance.
You can use the Array utility class
public static Object[] toObjectArray(Object array) {
int length = Array.getLength(array);
Object[] ret = new Object[length];
for(int i = 0; i < length; i++)
ret[i] = Array.get(array, i);
return ret;
}
Does java.lang.reflect.Array.get() do what you want?
Object result = method.invoke(clazz, (Object[])null);
Class<?> arrayKlazz = result.getClass();
if (arrayKlazz.isArray()) {
Class<?> klazz = result.getComponentType();
if (klazz == int.class) {
int[] intArray = arrayKlazz.cast(result);
}
}
It seems more appropiate to hold (primitive) arrays in an Object (result above).
Related
I am doing something like this :
public Object [] getApple() {
return new int[4];
}
But Java compiler does not allow this.
It says cannot convert from int[] to Object[].
While If I do something like this :
public Object getApple() {
return new int[4];
}
It compiles fine.
Can anyone explains why int [] cannot be cast to Object [] implicitly?
ints are not Objects, that is why. They are primitive data types, they play a special role and are not in the class tree with the all-parent Object.
The second example works because the int[] array itself can be interpreted as Object.
You can use the wrapper class Integer though, which is a subclass of Object:
public Object[] getApple() {
return new Integer[4];
}
You can work with it similar to an int[] due to auto-boxing. So if you do
Integer[] values = (Integer[]) getApple();
values[1] = 5;
Java will automatically box the 5 into the corresponding Integer object that represents 5 and then add this Integer to the array.
Same happens if you do
int val = values[2];
Java will unbox the value from the Integer object and give you an int since val is of type int.
Note that auto-boxing does not work for arrays, so Java won't automatically convert your int[] into an Integer[]. It only works for int to Integer and vice versa (analogously for the other primitives like double etc).
That is because array is an Object in Java. Hence when you try to return an int array as an Object, it was accepted.
However, when you tries to return an int array as array of Object it will be rejected because you are returning int array (an object) when the method return type is expecting (array of object).
public Object[] getApple() //expecting (array of object)
{
return new int[4]; //returning array (an object) Type mismatch!
}
If you run the following, it will be compilable:
public Object[] getApple() //expecting (array of object)
{
return new int[4][4]; //returning array of array (array of object) O.K!
}
Because you are returning a primitive int[] array, which is not a subtype of Object[]. You can return Integer[] instead.
Arrays have a specific type, and arrays of a subclass are not themselves subclasses of array of a superclass.
I'm look at dynamic arrays and I'm not sure what "Object" means for
protected void resize (int capacity) {
E[] temp = (E[]) new Object[capacity];
for (int k = 0; k < size; k++) {
temp[k] = data[k];
data = temp;
}
Cheers!
Every class has Object as a superclass, i.e. even if you write something like:
class A {}
then A implicitly extends Object. Because of this we can use variables of type Object to store any type:
Object x = new SomeClass();
and then to cast to the type we need when reading:
SomeClass someClass = (SomeClass) x;
Now, since we can not construct generic arrays, i.e. we can't do new T[], the only solution is to construct an "universal" (that can contain any type) array new Object[] and then to cast to the type wee need.
Its the root object that everything else derives from :
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html
Most IDE's enable you to click through and see the implmentation (ie ctrl+click on Object, and it will take you to its definition).
A new array of objects is being created, then casted (which is lame).
Object is the root of all classes in Java. In this case it is just being used to allocate memory for the references of whatever objects are stored in that array. You can store any type of Object in that array and cast it to another type at runtime like (MyClass) temp[3];
Since all objects extend Object this is just creating an array that can hold anything, so we copy all the contents of "data" one by one, and it doesn't matter what type they are since each item will definitely extend Object. Since you can't instantiate generic types (ie. new E[]()) you must use a type you can instantiate and cast to the generic - we can instantiate Object and cast to E safely.
"Object" means the Object class. In java, all other classes in inherit from the Object class. So, here you are declaring an array of any java type.
I have a class MyStack<T> which defines the following
public T[] toArray(){
int s=size();
#SuppressWarnings("unchecked")
T[] result=(T[])new Object[s];
Node n=first;
for (int i=0; i<s; i++){
result[i]=n.data;
n=n.next;
}
return result;
}
Since this returns an array of type T, I would think that if I declared this instance: MyStack<String> s=new MyStack<>, that the following would be perfectly valid: String[] test=s.toArray(). I think this because since s is of type String, toArray should return an array of type String, since String has basically been substituted in for every T in this class (only for this particular instantiation, I know). The only way this runs without errors is if I do this: Object[] test=s.toArray().
Why is this?
In a word, type erasure. Taken from the Java website:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
What this means is that, when your code is compiled, MyStack<String> is compiled into MyStack<Object>. This is to make sure that generics do not incur an overhead by needing to create new classes. How does this apply to you? Well..
MyStack<String> s = new MyStack<>();
is converted into..
MyStack<Object> s = new MyStack<>();
Now, this means that when you call the toArray method, the only type that can be guarenteed is the Object type. The compiler can't be sure that everything it returns is of type String, so it won't let you treat it as a String, due to the strong typing in Java. So, what is the only variable type left?
Object[] array = s.toArray();
Extra Reading
Type Erasure in Java.
Well, hold on a minute. Suppose your hypothesis were correct that String were substituted for every T.
Would the following cast be valid?
String[] result = (String[])new Object[s];
No, it would not. We can be sure that a new Object[] is not a String[].
Now sometimes you will see something like (T[])new Object[n] but it only works because the cast actually becomes erased inside the generic class. (It is a deceptive idiom.)
When the class gets compiled, what actually happens is that references to T are replaced with its upper bound (probably Object unless you had something like <T extends ...>):
public Object[] toArray(){
int s=size();
Object[] result=new Object[s];
Node n=first;
for (int i=0; i<s; i++){
result[i]=n.data;
n=n.next;
}
return result;
}
And the cast is moved to the call site:
MyStack stack = new MyStack();
String[] arr = (String[])stack.toArray();
So in fact, while the cast is erased inside the class, the cast does happen once the value is returned to outside the class, where ClassCastException is thrown.
The inability to instantiate arrays (and objects in general) generically is why the Collections framework defines their toArray method to take the return array as an argument. A simple version of this for you would be like the following:
public T[] toArray(T[] inArray){
int s = size();
Node n = first;
for (int i = 0; i < s; i++){
inArray[i] = n.data;
n = n.next;
}
return inArray;
}
For some ideas on how to create an array generically, you may see 'How to create a generic array in Java?'; however you will need the caller to pass some argument to the method.
This question already has answers here:
What is a wrapper class?
(17 answers)
Closed 8 years ago.
When reading the Hadoop material, always meet some Java concepts that I am not very familiar. With respect to the following one, what does the concept of "wrapper" mean here? When do we need this kind of wrapper, and what's the role it plays in an objected-oriented language?
Anytime you need to use a reference type (that is, an object - say Integer) as opposed to a primitive type (say int).
This is used, prominently, in generics where you need to specify a class as opposed to a primitive:
HashMap<String, Integer> foo = new HashMap<String, Integer>();
Here, you might think that:
HashMap<String, int> foo = new HashMap<String, int>();
would work, but it won't, as int is not a reference type (a class) but a primitive.
We have wrapper classes for all primitive types:
Integer for int, Byte for byte, Double for double, Character for char, etc.
The answers until now referred solely to the representations of a primitive type via a reference type.
But one of the main justifications for the existence of these writable wrappers in the context of Hadoop (or other contexts) was not mentioned yet:
You can write them!
That is, they allow some sort of "pass by reference", which usually is not possible in Java. Imagine you have a method like
public void computeSomething(int resultA, int resultB)
{
resultA = 123;
resultB = 234;
}
// Used as
int a = 0;
int b = 0;
computeSomething(a, b);
System.out.println(a); // Prints 0
System.out.println(b); // Prints 0
Obviously, modifying the arguments in the method has not effect for the outside world. In contrast to that, you can use the writable wrappers to achieve the desired effect:
public void computeSomething(IntWritable resultA, IntWritable resultB)
{
resultA.set(123);
resultB.set(234);
}
// Used as
IntWritable a = new IntWritable(0);
IntWritable b = new IntWritable(0);
computeSomething(a, b);
System.out.println(a); // Prints 123
System.out.println(b); // Prints 234
Wrapper classes provides a way to use the primitive types as objects like for int we have Integer as a wrapper class
Main use of Wrappers is with generics
like you can have an ArrayList<Integer>, but not an ArrayList<int> same with Other Collections etc. To get type safety we use generics and generics need objects not primitives.
and one more thing I want to add is, You use the wrappers when you need types that fit in the object oriented world.
A wrapper class is a class that contains another class or primitive type. The wrapper class is specifically made so that it provides additional functionality to the wrapped class of primitive type. One example of wrapper classes is with the java.lang.[Integer/Character/Float/etc], which can be used with generics, unlike primitive types.
As another example, imagine I want to add additional functionality to a String. String is final, so I can't extend it. However, I can make a wrapper class:
class StringWrapper
{
public String str;
public StringWrapper(String str)
{
this.str = str;
}
public void reverse()
{
char[] temp = new char[str.length()];
for(int i = 0; i < str.length(); i++)
{
temp[str.length() - i] = str.charAt(i);
}
str = new String(temp);
}
}
I can then say:
StringWrapper strW = new StringWrapper("abc");
strW.reverse();
System.out.println(strW.str);
Which outputs:
cba
I have the following code in Java:
public static<T> void doIt(Class<T> t)
{
T[] arr;
arr = (T[])Array.newInstance(t, 4);
}
I want to be able to use doIt using both primitive type such as double and using class objects such as String.
I could do it by using (code compiles):
doIt(double.class);
doIt(String.class);
However, I am worried that in the first case, the Java compiler will actually wrap the double primitive type using a Double class, which I don't want. I actually want it to instantiate a primitive array in this case (while instantiating an objects array with the String case). Does someone know what happens with doIt(double.class)? Is it instantiated as Double or double?
Thanks.
You couldn't actually make T = double here - Java generics simply don't work with primitive types. However, you can still instantiate your array:
import java.lang.reflect.*;
public class Test {
public static void main(String[] args) {
createArray(double.class);
}
private static void createArray(Class<?> clazz) {
Object array = Array.newInstance(clazz, 4);
System.out.println(array.getClass() == double[].class); // true
}
}
It really depends on what you want to do with the array afterwards.
You can make an array of primitive double like this:
double[] arr = (double[]) Array.newInstance(double.class, 0);
But you can't make this work with generics, because generic parameters are always reference types, not primitive types.
Generics will work with objects so it should be a Double after boxing.
You can create a method that takes an array type instead of the element type and get around the problem that type parameters must be reference types since all array types are reference types.
<T> T doIt(Class<T> arrayType) {
assert arrayType.getElementType() != null;
return <T> Array.newInstance(arrayType.getElementType(), 4);
}