|
|
Start of Tutorial > Start of Trail > Start of Lesson |
Search
Feedback Form |
One of the changes in JDK 5.0 is that the classjava.lang.Classis generic. It's an interesting example of using genericity for something other than a container class.Now that
Classhas a type parameterT, you might well ask, what doesTstand for? It stands for the type that theClassobject is representing.For example, the type of
String.classisClass<String>, and the type ofSerializable.classisClass<Serializable>. This can be used to improve the type safety of your reflection code.In particular, since the
newInstance()method inClassnow returns aT, 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:
You can call this either asinterface 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; }or you can declare a classselect(new Factory<EmpInfo>(){ public EmpInfo make() { return new EmpInfo(); }} , "selection string");EmpInfoFactoryto support theFactoryinterfaceand call itclass EmpInfoFactory implements Factory<EmpInfo> { ... public EmpInfo make() { return new EmpInfo();} }The downside of this solution is that it requires either:select(getMyEmpInfoFactory(), "selection string");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:
- the use of verbose anonymous factory classes at the call site, or
- declaring a factory class for every type used and passing a factory instance at the call site, which is somewhat unnatural.
However, this would not give us a collection of the precise type we desire. Now thatCollection 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; }Classis generic, we can instead write the following:The above code gives us the precise type of collection in a type safe way.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.
|
|
Start of Tutorial > Start of Trail > Start of Lesson |
Search
Feedback Form |
Copyright 1995-2005 Sun Microsystems, Inc. All rights reserved.