Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
202
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

Reflection

Packages

java.lang.reflect

Use: J2SE (since JDK 1.1)

Overview

The reflection API allows you to discover information about classes and objects at runtime. This capability is called introspection, and is useful when you want to dynamically include new classes in your programs while they are running. Using reflection, you can load a class dynamically using only its name.

Although most of the API is in java.lang.reflect, you should also regard java.lang.Class as part of this API . The class Class acts as a gateway to the reflection functionalities. The reflection API defines several classes that encapsulate the different types of information, classes like Method, Field, Constructor, and Modifier. These classes are final and, except for the Modifier, only the JVM can create instances of these types.

Thanks to this API, you can dynamically use instances of previously unknown origin; for instance, when the class of an object is

unknown at the time of development. You can invoke methods, call constructors, modify fields, create new arrays, and access and modify their elements.

Example 6.3 Using instances of unknown origin

Class class = Class.forName("some class name");

Object o = class.newInstance();

The code demonstrates how you can create an object from only having the name of the class. The method forName takes a String as argument and tries to locate a class file matching that name and loads that class in the class loader. The method returns an instance of Class which describes the class. When newInstance is called on the Class object it creates an instance using the constructor with no arguments. The String could be read from a file, property or other source.

When you receive an object from somewhere and you want to find out the specific type of the instance, use code similar to the following code. The method getClass returns the Class instance describing the class of the object. The method getName returns the name of the Class.

It can be useful sometimes during debugging, when you don’t know the type of a received object:

Object unknownTypeObject = //received somehow

System.out.println(unknownTypeObject.getClass().getName());

An addition to the Reflection API was made when J2SE v1.3 was released. As of 1.3, you can use the dynamic proxy class. The class is created at runtime and implements a number of interfaces specified at runtime. The Proxy class, which is responsible for creating this class, also acts as the superclass to every proxy.

The method to create an instance of the dynamic proxy takes three arguments: a ClassLoader, an array of interfaces, and an InvocationHandler. The proxy instance created delegates all method calls to the InvocationHandler, which is responsible for carrying them out. To keep the invocation as generic as possible, the InvocationHandler implements a single method, invoke.

The Reflection API provides many advanced features, many of which the average developer will never use. The flexibility that reflection offers through these advanced features comes at a price, which is performance. According to Effective Java [Bloch01], interfaces should be preferred to reflection.

However, this doesn't mean that reflection is obsolete. Certain applications can receive great benefits from reflection, particularly those based on JavaBeans, object inspectors, interpreters, and services like object serialization, which need to get information on an object at runtime.

Pattern Use

Factory Method (see page 21): The Factory Method pattern is used to create instances without having to call a constructor directly. It also enables you to gain the option of returning different types instead of just the class of

197

the constructor called. Given the dynamic nature of the dynamic proxy, using a regular constructor wouldn't work, because you need to know the name of the class/ constructor before you can invoke it. When using a constructor is out of the question, the next best thing is a static method to create an instance. The class Proxy has two factory methods; one (getProxyClass) gets the Class object that describes the dynamic proxy with the specified interfaces. The other factory method (newProxyInstance) is more of a convenience method. It uses the getProxyClass method to get the class, then uses that Class to get the constructor and invoke the constructor.

The Array class, which is the wrapper class for arrays implements the Factory Method for a different reason. Creating an array requires knowing the exact type of the elements, and the resulting object is an array of elements of that particular type, which cannot be changed later. This is like the normal array where you declare the type when the array is created and cannot be changed. The object created by the factory method is not an instance of Array, which eliminates the possibility of using a constructor, because the constructor of Array returns an Array instance. So instead of a constructor, a Factory Method is used.

Facade (see page 175): In this API the class Class acts as a front to the whole reflection of a real class. The most-used options are available through the Class. The other reflection classes are still available for more specialized modification, invocation, or reflection.

Proxy (see page 197): The classes Field, Method and Constructor encapsulate the whole concept of a specific field, method, or constructor respectively. You can request all information through the reflection classes. For example, using a Method object, which is tied to a specific method in a class, you can request the declared modifiers, a list of parameter types required to invoke the method, and the return type. You can even use the Method object to invoke the method.

The Method class acts as a proxy to the specific method. Instead of being a proxy to another object, here the Field, Method, Constructor, and Modifier are proxies to parts of an object.

Another implementation of the Proxy pattern is the Proxy class. The factory method in the Proxy class creates the required class for the needed functionality. The resulting subclass of Proxy implements all specified interfaces and methods. The implementation of the methods are such that all calls are forwarded to the single handler method inside of the InvocationHandler.

To the outside world, an instance of the dynamic proxy behaves as expected. All of its interfaces and all defined methods can be invoked on the proxy instance. The real implementation of the methods is in the

InvocationHandler.

198