java.lang.Class is
generic. It's an interesting example of using genericity for something
other than a container class.
Now that Class has a type parameter T, you might well ask,
what does T stand for? It stands for the type that the Class
object is representing.
For example, the type of String.class is
Class<String>, and the type of Serializable.class is
Class<Serializable>. This can be used to improve the type safety
of your reflection code.
In particular, since the newInstance() method in Class now
returns a T, you can get more precise types when creating objects
reflectively.
For example, suppose you need to write a utility method that performs a database query, given as a string of SQL, and returns a collection of objects in the database that match that query.
One way is to pass in a factory object explicitly, writing code like:
interface Factory<T> { T make();}
public <T> Collection<T> select(Factory<T> factory, String statement) {
Collection<T> result = new ArrayList<T>();
/* Run sql query using jdbc */
for (/* Iterate over jdbc results. */) {
T item = factory.make();
/* Use reflection and set all of item's fields from sql results. */
result.add(item);
}
return result;
}
select(new Factory<EmpInfo>(){ public EmpInfo make() {
return new EmpInfo();
}}
, "selection string");
EmpInfoFactory to
support the Factory interface
class EmpInfoFactory implements Factory<EmpInfo> {
...
public EmpInfo make() { return new EmpInfo();}
}
select(getMyEmpInfoFactory(), "selection string");
Collection emps = sqlUtility.select(EmpInfo.class, "select * from emps");
...
public static Collection select(Class c, String sqlStatement) {
Collection result = new ArrayList();
/* Run sql query using jdbc. */
for (/* Iterate over jdbc results. */ ) {
Object item = c.newInstance();
/* Use reflection and set all of item's fields from sql results. */
result.add(item);
}
return result;
}
Class is generic, we can instead write
the following:
Collection<EmpInfo> emps =
sqlUtility.select(EmpInfo.class, "select * from emps");
...
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
Collection<T> result = new ArrayList<T>();
/* Run sql query using jdbc. */
for (/* Iterate over jdbc results. */ ) {
T item = c.newInstance();
/* Use reflection and set all of item's fields from sql results. */
result.add(item);
}
return result;
}
This technique of using class literals as run time type tokens is a very useful trick to know. It's an idiom that's used extensively in the new APIs for manipulating annotations, for example.