Tech News

Other words from Reflection

Reflection

The package java.lang.reflect contains the reflection package, the classes you can use to examine a type in detail. You can write a complete type browser using these classes, or you can write an application that interprets code that a user writes, turning that code into actual uses of classes, creation of objects, invocations of methods, and so on. Almost all the types mentioned in this discussion on reflection are contained in the package java.lang.reflect, except for the classes Class and Package, which are part of the package java.lang, and Annotation, which is part of the java.lang.annotation package.

Reflection starts with a Class object. From the Class object you can obtain a complete list of members of the class, find out all the types of the class (the interfaces it implements, the classes it extends), and find outgiven the fully qualified name of a class (such java.lang.String) the program first tries to obtain a Class object for that class, using the static method Class.forname. If the class can’t be found an exception is thrown which the program catches and reports. Otherwise, the simple name of the classstring, for exampleis printed. Next the Class object is asked for its superclass’s Class object.

As long as the named class is not Object and is a class rather than an interface, getsuperclass will return a superclass’s Class object. The name of the super class is printed in full using getcanonicalname (there are a number of ways to name a class as you’ll see in Section 16.1.4 on page 411). Next, the Class object is asked for all the methods that it declares. The declared methods include all methods actually declared in the class but none that are inherited. Since we’re only interested in public methods, we ask the Method object for the method’s modifiers and ask the Modifier class if those modifiers include public. If so the method is printed, otherwise it is ignored. Here’s the output when given the name of the Attr class from page 76:

The Class Class

There is a Class object for every type. This includes each class, enum, interface, annotation, array, and the primitive types. There is also a special Class object representing the keyword void. These objects can be used for basic queries about the type and, for the reference types, to create new objects of that type. The Class class is the starting point for reflection. It also provides a tool to manipulate classes, primarily for creating objects of types whose names are specified by strings, and for loading classes using specialized techniques, such as across the network. We look in more detail at class loading in Section 16.13 on page 435. You get a Class object in four ways: ask an object for its Class object using its getclass method; use a class literal (the name of the class followed by .class, as in String.class); look it up by its fully qualified name (all packages included) using the static method Class.forname; or get it from one of the reflection methods that return Class objects for nested classes and interfaces (such as

Type Tokens

Class is a generic class, declared as Class. Each Class object for a reference type is of a parameterized type corresponding to the class it represents. For example, the type of String.class is Class, the type of Integer.class is Class, and so forth. The type of the Class object for a primitive type is the same type as that of its corresponding wrapper class. For example, the type of int.class is Class, but note that int.class and Integer.class are two different instances of the same type of class. Parameterized types all share the Class object of their raw typefor example, the Class object for List is the same as that for List and the same as that for List.class, and its type is Class.

Last word

After the main method is the declaration of the output stream to use, by default System.out. The String arrays are described shortly. The printtype method prints its own type parameter’s description and then invokes itself recursively to print the description of type’s supertypes. Because we initially have general Type objects, we first have to convert them to Class objects. The depth parameter keeps track of how far up the type hierarchy it has climbed, indenting each description line according to its depth. The depth is incremented at each recursion level. The labels array specifies how to label the class labels[0] is the label if the type is a class; labels[1] is for interfaces; labels[2] for enums; and labels[3] for annotation types. Note the order in which we check what kind of type we haven enum type is a class, and an annotation type is an interface, so we have to check for these more specific kinds of type first. Three arrays are defined for these labels: basic is used at the top level, supercl is used for super classes, and iface is used for super interfaces of interfaces, which extend, not implement, each other. After we print the right prefix, we use get can onicalname to print the full name of the type. The Class class provides a testing method, but it already adds “class” or “interface” in front. We want to control the prefix, so we must create our own implementation. We look more at class names a little later.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button