The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.
See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.
One of the changes in JDK 5.0 is that the class 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; }
You can call this either as
select(new Factory<EmpInfo>(){ public EmpInfo make() { return new EmpInfo(); }}, "selection string");
or you can declare a class EmpInfoFactory
to support the Factory
interface
class EmpInfoFactory implements Factory<EmpInfo> { ... public EmpInfo make() { return new EmpInfo(); } }
and call it
select(getMyEmpInfoFactory(), "selection string");
The downside of this solution is that it requires either:
It is natural to use the class literal as a factory object, which can then be used by reflection. Today (without generics) the code might be written:
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; }
However, this would not give us a collection of the precise type we desire. Now that 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; }
The above code gives us the precise type of collection in a type safe way.
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.