Reflection reflection API, which enables programmers to make

Reflection

Blerta Haxhijaha

We Will Write a Custom Essay Specifically
For You For Only $13.90/page!


order now

I.       
Introduction

Reflection is a dynamic language
feature which allows programs to inspect objects at runtime, thus determine the
characteristics and capabilities they poses. Reflection provides information
about the class that the object belongs to, the class’ constructors, methods
and fields, interfaces that the class implements and any superclass available.
Reflection then gives the possibility to act upon the retrieved information,
namely to create instances of the class types discovered, to invoke the
retrieved methods, and even to set fields that were discovered to belong to the
examined object’s class. Via reflection, it is also possible to access fields
and methods that are declared private. Java comes with its own reflection API,
which enables programmers to make use of the capabilities mentioned above.

One of
the most common uses of reflection is in the development of programming tools –
it is what enables the integrated development environments such as BlueJ, to list us the methods available
in a class the moment that we type the class name. Schema generation is also
something that benefits from reflection, i.e., it is possible to generate the
schema for any type by inspecting every field or property of that type with
reflection. Again thanks to reflection, JUnit
is able to dynamically invoke all methods of a class under test whose names
start with the literal “test”.

However,
the powerful features of reflection come with certain implications. Firstly,
there is some performance overhead associated with reflection. This performance
overhead results from the need to dynamically resolve types when using
reflection, which implies that the Java virtual machine is unable to perform
certain optimizations. Consequently, it is advised that reflection be avoided
whenever possible in performance-sensitive programs. Secondly, code using
reflection breaks abstractions, due to the possibility of accessing private
fields and invoking private methods. This can result in unexpected and
unpredictable side-effects, eventually rendering the code dysfunctional.

II.       
Related
Work

There has been an extensive amount
of both research papers and published books, which explore the idea,
application and power related to reflection, as well as its limitations and
performance overhead. I have made a selection of a few research papers that
have examined reflection from different perspectives, and will provide a short
summary of each below.

In their paper Reflection in logic, functional and
object-oriented programming: a Short Comparative

Study 1, F.N. Demers and J.Malenfant
argue that even though reflection as a concept has been around for quite some
time, its exploration in the different programming paradigms – logic,
functional and object oriented programming– has been quite isolated, with
little interaction between the experts of these sub-domains. The authors argue
that this has contributed to a reduced cross-fertilization of advances made
within each paradigm. They hence provide a historic perspective of the
development of reflection in each paradigm, specifying the similarities and
differences when compared to the other two, in an attempt to encourage a closer
collaboration between the actors of the separate sub-domains.

In Code Reuse Through Reflection: An Empirical
Perspective 2, authors Y. Hassoun, R. Johnson, S. Counsell have explored
the potential of reflection in enabling the much desired possibility of code
reuse. They stipulate that it is possible to decompose object-oriented systems
into two parts: an application part, and a reusable part. Their work focuses on
how to identify the reusable part, and refactor it using reflection techniques.
This refactored part is then re-integrated in the initial system. The authors
use well-established metrics that measure the degree of reusability, proposed
by Y. Chen more than 2 decades ago, in order to measure the increase in
reusability after introducing reflection in the system. However, the described
process is a rather costly undertake, which requires heavy resources in order
to transform the object-oriented systems in the manner proposed.

Another
paper, titled Reflection Support: Java
Reflection Made Easy 3, by authors Z. Shams and S. H. Edwards, tries to
solve the issue of the programming overhead involved when using reflection in
code development. They recognize the power associated with reflection and the
possibilities it brings, but are concerned with the end result of a code that
is difficult to read, bulky to write and not very intuitive to maintain. The
authors have used a representative class of programs in order to measure the
increase in code size that is a direct result of using reflection (since
reflection requires numerous try-catch blocks of checked exceptions, explicit
casts, and multiple lines of code for basic actions). They have found that the
code size increases by a factor of three when using Java’s reflection API, in
comparison to the non-reflective Java code counterpart. In order to overcome
this issue, they propose the usage of another library, called ReflectionSupport, which is a simplified
API that also enables reflection. This library uses similar method names as the
native Java reflection API, but it internally takes care of exception handling,
explicit casts and some other declarations required in reflection. The result
of using the ReflectionSupport library
is code reduced in size, less error-prone and easier to maintain.

The next
paper, Challenges for Static Analysis of
Java Reflection – Literature Review and Empirical Study 4, by authors D.
Landman, A. Serebrenik and J. J. Vinju, discusses reflection from another
interesting perspective – the difficulties it causes to static code analyzers.
Developers are used to exploiting the benefits of static code analyzers as part
of their integrated development environments, which are apt at discovering bugs
and issuing warnings, detecting repetitive code, validating code syntax and
suggesting appropriate refactoring. However, dynamic language features such as
reflection, pose significant challenges even to state-of-the-are static code
analyzers, due to their unpredictability. The paper explores the advances that
are made in recent years, in the efforts to make static code analyzers more
reflection-aware. For the needs of this paper, the authors have examined a pool
of 461 Java open-source projects, and have found that no less than 78% of them
use some form of reflection as a dynamic language feature.

The last
paper, Exploiting Reflection in Object
Oriented Genetic Programming 5, by author S.M.Lucas, explores the
prospects of using reflection in genetic programming. Genetic programming is a
promising technique in the artificial intelligence domain, which seeks to
automatically solve a problem by starting with a large base of simple computer
programs, and evolve them into a sophisticated computer program that solves the
high-level task. It tries to do this by using methods analogous to the naturally
occurring genetic processes, such as the genetic crossover (recombination)
process, in order to produce a resulting computer program, which contains the
best traits from the computer programs of the entry pool. The author argues
that object oriented genetic programming is an under-explored area, yielding
only 32 pages of Google search results, as opposed to 75,900 result pages when
searching for the “Genetic Programming” term. He then proceeds to
explaining that, for the needs of genetic programming, it is relatively
straightforward to generate random computer programs as a sequence of method
invocations on a set of objects, with the help of reflection. However, he warns
against the fact that using reflection to make method invocations is slower than
making a direct method call.

III.        
The
Java Reflection API

The Java platform enables
reflection through the java.lang.reflect package,
which has been available since JDK1.1 edition. The 6 classes found in this
package (Array, Constructor, Field,
Package, Method, Proxy) along with the two classes from java.lang (Class and ClassLoader), provide a solid foundation for exploiting the
possibilities that come with reflection. The API contains several other classes
too, and a total set of 181 public methods. Figure (1) gives a preview of the
most important classes from the Java reflection API.

The Class class from the Java Reflection API provides a wealth of
information related to a given object’s class. From the interfaces it
implements, to the superclass it inherits from; all the methods, constructors
and fields of the class, as well as the ones belonging to the superclass and
interfaces; can be retrieved from the java.lang.Class.
The information that this class provides, as well as the methods used to obtain
each piece of information, are shown in Figure (2).

Reflection
enables dynamic operations with objects as well, through object instantiations,
method invocations, as well as direct field modifications. In order to
instantiate new objects, dedicated methods from the reflection API are used,
depending on the intention to invoke the default class constructor, or some
other custom constructor with parameters.

When it
comes to method calls, it is enough to supply the name of the method as a
string literal, and the method can subsequently be invoked. Care needs to be
taken, however, to supply the necessary entry parameters of the method to be
invoked as well, if that method has any. This is required in order to avoid
confusion in cases when several overloads of the same method are present in the
class. The object fields can be modified as well, via special getter and setter
methods of the API. It is possible even to ignore the security restriction of
non-public methods and fields,

via
special directives of the API which set these members as accessible.

Next, we move to showing all the
reflection possibilities via two example Java projects. The first project will
demonstrate the power of reflection to dynamically retrieve information about a
given object’s class. The second project will show how reflection can be used
to dynamically manipulate and change the state of objects.

Figure (3) shows the code for class
Car, which contains three private
fields of different types, a default constructor and one constructor with an
integer entry parameter, three instance methods, and one static method.

The Main class in figure (4) is used to
inspect the features of the Car class
via reflection. It does so by primarily retrieving the class of the given
object, via the getClass() directive.

After
obtaining the object’s class in a Class reference,
it proceeds with inspecting the class’ methods, with the getDeclaredMethods() directive. This method returns all the public
and non-public methods of the class under inspection. It is also possible to
retrieve the public methods of the direct and indirect superclasses of the
class as well, via method getMethods().
Next, the parameter counts of the retrieved methods are inspected with getParameterCount(). Further in the
code, the interfaces that the class implements, and the superclass it inherits
from, are retrieved, with methods getInterfaces()
and getSuperclass(),
respectively. The class constructors are then inspected with getDeclaredConstructors(), which returns
an array of Constructor objects. The array is iterated

in order to get the constructor
parameter types and count (getType() and
getParameterCount()). The main method
finishes by retrieving the class fields (getDeclaredFields())
which are returned as an array of Field
objects. Finally, a specific field is retrieved by providing its name as a
string literal in method getDeclaredField(“fieldName”).

Next, we proceed with the second
example, which demonstrates how reflection can enable the manipulation of
objects. For this purpose, we use class RentCar,
which contains several private fields, two constructors, a static method and a
collection of private and public instance methods, as shown in Figure (5). The
class used to work with objects of this class via reflection is shown in Figure
(6). Note that, just like in the previous example, the java.lang.reflect.* package is imported, because this is where the
Java Reflection API is found.

The main
method begins by retrieving the class of the object we want to work with. As
shown in the previous example, this is done by using the getClass() directive. The retrieved class is then places in a Class reference. Next, we instantiate a
new instance of the retrieved class, by using the newInstance() method. This method creates the object by using the
default (or parameterless) constructor. Note that if a parameterless
constructor does not exist in the class, the method will generate an exception.
It is also possible to create an object of the class by using any of

the
constructors available, as shown in the following section of the code, where
all the class’ constructors are first retrieved, and then the second
constructor is used to create a new object (ctors1.newInstance(parameterValue)).
In case the input parameters are incorrect for the constructor in use, an IllegalArgumentException is thrown.

Next,
we show how methods are invoked. We saw in the previous example that reflection
enables us to retrieve the methods of the given class. Now we use the name
literal of any

of
the retrieved methods in order to retrieve the Method object corresponding to that method (getDeclaredMethod(“methodName”)). Then we use the directive invoke(objectName, methodParams) upon
the method object, by providing as input parameters the class object upon which
we want

to
call the method, as well as any input parameters of the method to be invoked.
We show that private methods can also be invoked, by first setting their
accessibility to true (setAccessible()).
Static methods are called in a similar fashion, with null as the value for the object-to-be-called-upon
parameter. Finally, we show that the class fields can be modified directly
with the set() method of the Field class.

IV.       
Conclusion

Reflection is a powerful mechanism
in the programming world, and the Java programming language comes with its own
potent reflection API. Reflection enables the retrieval of information on types
and methods we use at runtime. This is especially useful on cases when at
compile time, we do not have information on these types and methods, and we
need to resolve them dynamically. Reflection also enables us to act upon the
retrieved information, namely to instantiate new objects of the retrieved
types, and to invoke the retrieved methods.

In this
paper, the possibilities that come with reflection were explored, its uses in
real-world applications, as well as the limitations associated with it. A
section looking at some related research work on reflection was also provided,
along with a summary of several papers which looked at reflection from very
different perspectives.

Finally,
it is crucial to point out that reflection is a rather advanced feature, and
that it should be used sparingly. Even the Oracle Java documentation 7
advises that reflection should be used only by developers who have a solid
understanding of the language, and only in cases when using direct method calls
and object instantiation is simply not possible. Having said that, reflection
remains to be categorized as a powerful technique that enables developers to
provide solutions to tasks, which would otherwise be impossible to complete.

x

Hi!
I'm James!

Would you like to get a custom essay? How about receiving a customized one?

Check it out