1. Here are some really good ones about reflection and primitives.
Java's reflection code has incorporated an assortment of kludges to be able to handle primitives. A few examples:
a. There are times when using the reflection API "magic" happens with regard to primitive types and wrapper classes. Sometimes, we expect a primitive but instead get an instance of a wrapper. Conversely, at times we must remember to wrapper primitives before passing them as arguments to reflection methods.
Given the following code:
public class Tester {
public boolean test (int i) {
return i > 3;
}
}
The method takes an int and returns a boolean. Yet to invoke it via reflection I need to pass it an Integer object and I receive back a Boolean object. Here is the code:
Object[] args = new Object[1];
args[0] = new Integer(3);
Boolean result = (Boolean)m.invoke(t,args);
In short, if I invoke test via a normal method call I pass it an int (primitive) and it returns a boolean (primitive). If I invoke test via reflection I need to pass it an Integer (object) and it returns a Boolean object, does that make sense????
b. Every object is an instance of a class and I can obtain the Class instance at runtime by calling getClass(). However, primitives, have no class and therefore the following is not allowed:
int i = 1;
i.getClass();
However, I can get a Class object for a primitive in a number of ways. For example:
class Test {
public int i;
}
Test test = new Test();
Class c = test.getClass();
Field fieldi = c.getField("i");
Class classOfI = fieldI.getType();
I now have a a Class object for int!!
classOfI.getName(); //returns int
We can ask it its name, and we find that we have a Class named "int." Realizing part of the problem, the developers of Class included a message to ask if the Class is a primitive:
classForI.isPrimitive() // returns true
But, how can a Class be a primitive? What does that mean???
There are other ways to get a Class object. We can say:
Class class = int.class;
and obtain a Class object whose name is int. Yet we cannot do the following:
Class.forName("int");
this does work for regular classes such as:
Class.forName("java.lang.String");
In short Java's reflection code has incorporated a series of kludges to be able to handle primitives. We have classes that are primitives, somethings work somethings don't, etc.
2. Because of primitive types polymorphism and thus a big piece of
good object-oriented design is defeated and we need to code special
cases for primitives. For example: String needs 8 different valueOf
methods to deal with all the primitive types. Here is the code:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
This should be all that is needed, an Object decides how it is printed (in fact even this method has a problem in that it needs to explicitly check for null and handle it, in a real OO language like Smalltalk, nil knows how to print itself). However for primitives we need to take a procedural approach, the decidison is made by code separate from data.
public static valueOf(boolean b) {
return b ? true: false;
}
3.Primitive variables cannot be used wherever objects can be used;
You can't have a collection of int's