Section 5.13. Types, Reflection, and Dynamic Loading


5.13. Types, Reflection, and Dynamic Loading

The java.lang.Class class represents data types in Java and, along with the classes in the java.lang.reflect package, gives Java programs the capability of introspection (or self-reflection); a Java class can look at itself, or any other class, and determine its superclass, what methods it defines, and so on.

5.13.1. Class Objects

You can obtain a Class object in Java in several ways:

 // Obtain the Class of an arbitrary object o Class c = o.getClass(); // Obtain a Class object for primitive types with various predefined constants c = Void.TYPE;          // The special "no-return-value" type c = Byte.TYPE;          // Class object that represents a byte c = Integer.TYPE;       // Class object that represents an int c = Double.TYPE;        // etc; see also Short, Character, Long, Float  // Express a class literal as a type name followed by ".class" c = int.class;          // Same as Integer.TYPE c = String.class;       // Same as "dummystring".getClass() c = byte[].class;       // Type of byte arrays c = Class[][].class;    // Type of array of arrays of Class objects 

5.13.2. Reflecting on a Class

Once you have a Class object, you can perform some interesting reflective operations with it:

 import java.lang.reflect.*; Object o;                   // Some unknown object to investigate Class c = o.getClass();     // Get its type // If it is an array, figure out its base type while (c.isArray()) c = c.getComponentType(); // If c is not a primitive type, print its class hierarchy if (!c.isPrimitive()) {   for(Class s = c; s != null; s = s.getSuperclass())      System.out.println(s.getName() + " extends"); } // Try to create a new instance of c; this requires a no-arg constructor Object newobj = null; try { newobj = c.newInstance(); } catch (Exception e) {    // Handle InstantiationException, IllegalAccessException } // See if the class has a method named setText that takes a single String // If so, call it with a string argument try {     Method m = c.getMethod("setText", new Class[] { String.class });     m.invoke(newobj, new Object[] { "My Label" }); } catch(Exception e) { /* Handle exceptions here */ } // These are varargs methods in Java 5.0 so the syntax is much cleaner. // Look for and invoke a method named "put" that takes two Object arguments try {     Method m = c.getMethod("add", Object.class, Object.class);     m.invoke(newobj, "key", "value"); } catch(Exception e) { System.out.println(e); } // In Java 5.0 we can use reflection on enumerated types and constants Class<Thread.State> ts = Thread.State.class;  // Thread.State type if (ts.isEnum()) {  // If it is an enumerated type     Thread.State[] constants = ts.getEnumConstants(); // get its constants } try {     Field f = ts.getField("RUNNABLE");       // Get the field named "RUNNABLE"     System.out.println(f.isEnumConstant());  // Is it an enumerated constant? } catch(Exception e) { System.out.println(e); } // The VM discards generic type information at runtime, but it is stored // in the class file for the compiler and is accessible through reflection try {      Class map = Class.forName("java.util.Map");     TypeVariable<?>[] typevars = map.getTypeParameters();     for(TypeVariable<?> typevar : typevars) {         System.out.print(typevar.getName());         Type[] bounds = typevar.getBounds();         if (bounds.length > 0) System.out.print(" extends ");         for(int i = 0; i < bounds.length; i++) {             if (i > 0) System.out.print(" & ");             System.out.print(bounds[i]);         }         System.out.println();     } } catch(Exception e) { System.out.println(e); } // In Java 5.0, reflection can also be used on annotation types and to // determine the values of runtime visible annotations Class<?> a = Override.class;  // an annotation class if (a.isAnnotation()) {       // is this an annotation type?     // Look for some meta-annotations     java.lang.annotation.Retention retention =         a.getAnnotation(java.lang.annotation.Retention.class);     if (retention != null)          System.out.printf("Retention: %s%n", retention.value()); } 

5.13.3. Dynamic Class Loading

Class also provides a simple mechanism for dynamic class loading in Java. For more complete control over dynamic class loading, however, you should use a java.lang.ClassLoader object, typically a java.net.URLClassLoader . This technique is useful, for example, when you want to load a class that is named in a configuration file instead of being hardcoded into your program:

 // Dynamically load a class specified by name in a config file String classname =                     // Look up the name of the class     config.getProperty("filterclass",  // The property name                        "com.davidflanagan.filters.Default"); // A default try {   Class c = Class.forName(classname);  // Dynamically load the class   Object o = c.newInstance();          // Dynamically instantiate it } catch (Exception e) { /* Handle exceptions */ } 

The preceding code works only if the class to be loaded is in the class path . If this is not the case, you can create a custom ClassLoader object to load a class from a path (or URL) you specify yourself:

 import java.net.*; String classdir = config.getProperty("filterDirectory"); // Look up class path try {   ClassLoader loader = new URLClassLoader(new URL[] { new URL(classdir) });   Class c = loader.loadClass(classname); } catch (Exception e) { /* Handle exceptions */ } 

5.13.4. Dynamic Proxies

The Proxy class and InvocationHandler interface to the java.lang.reflect package were added to Java 1.3. Proxy is a powerful but infrequently used class that allows you to dynamically create a new class or instance that implements a specified interface or set of interfaces. It also dispatches invocations of the interface methods to an InvocationHandler object.



Java In A Nutshell
Java In A Nutshell, 5th Edition
ISBN: 0596007736
EAN: 2147483647
Year: 2004
Pages: 1220

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net