In the final section of this chapter, we discuss proxies, a feature that became available with Java SE 1.3. You use a proxy to create at runtime new classes that implement a given set of interfaces. Proxies are only necessary when you don’t yet know at compile time which interfaces you need to implement. This is not a common situation for application programmers, and you should feel free to skip this section if you are not interested in advanced wizardry. However, for certain system programming applications, the flexibility that proxies offer can be very important.
Suppose you want to construct an object of a class that implements one or more interfaces whose exact nature you may not know at compile time. This is a difficult problem.
To construct an actual class, you can simply use the newInstance method or use reflection to find a constructor. But you can’t instantiate an interface. You need to define a new class in a running program.
To overcome this problem, some programs generate code, place it into a file, invoke the compiler, and then load the resulting class file. Naturally, this is slow, and it also requires deployment of the compiler together with the program. The proxy mechanism is a better solution. The proxy class can create brand-new classes at runtime. Such a proxy class implements the interfaces that you specify. In particular, the proxy class has the following methods:
However, you cannot define new code for these methods at runtime. Instead, you must supply an invocation handler. An invocation handler is an object of any class that implements the Invocation Handler interface. That interface has a single method:
Object invoke(Object proxy, Method method, Object args) Whenever a method is called on the proxy object, the invoke method of the invocation handler gets called, with the Method object and parameters of the original call. The invocation handler must then figure out how to handle the call.
To create a proxy object, you use the newProxyInstance method of the Proxy class. The method has three parameters:
In our example program, we use proxies and invocation handlers to trace method calls.
We define a TraceHandler wrapper class that stores a wrapped object. Its invoke method simply prints the name and parameters of the method to be called and then calls the method with the wrapped object as the implicit parameter.
Here is how you construct a proxy object that causes the tracing behavior whenever one of its methods is called:
Now, whenever a method from one of the interfaces is called on proxy, the method name and parameters are printed out and the method is then invoked on value.
In the program shown in Listing below, we use proxy objects to trace a binary search. We fill an array with proxies to the integers 1 . . . 1000. Then we invoke the binarySearchmethod of the Arrays class to search for a random integer in the array. Finally, we print the matching element.
The Integer class implements the Comparable interface. The proxy objects belong to a class that is defined at runtime. (It has a name such as $Proxy0.) That class also implements the Comparable interface. However, its compare To method calls the invoke method of the proxy object’s handler.
NOTE: As you saw earlier in this section, as of Java SE 5.0, the Integer class actually implements Comparable<Integer>. However, at runtime, all generic types are erased and the proxy is constructed with the class object for the raw Comparable class. The binarySearch method makes calls like this:
Because we filled the array with proxy objects, the compareTo calls call the invoke method of the Trace Handler class. That method prints the method name and parameters and then invokes compareTo on the wrapped Integer object.Finally, at the end of the sample program, we call
The println method calls toString on the proxy object, and that call is also redirected to the invocation handler.Here is the complete trace of a program run: 500.compareTo(288) 250.compareTo(288) 375.compareTo(288) 312.compareTo(288) 281.compareTo(288) 296.compareTo(288) 288.compareTo(288) 288.toString()
You can see how the binary search algorithm homes in on the key by cutting the search interval in half in every step. Note that the toString method is proxied even though it does not belong to the Comparable interface—as you will see in the next section, certain Object methods are always proxied.
Properties of Proxy Classes
Now that you have seen proxy classes in action, we want to go over some of their properties. Remember that proxy classes are created on the fly in a running program. However, once they are created, they are regular classes, just like any other classes in the virtual machine.
All proxy classes extend the class Proxy. A proxy class has only one instance field—the invocation handler, which is defined in the Proxy superclass. Any additional data that are required to carry out the proxy objects’ tasks must be stored in the invocation handler. For example, when we proxied Comparable objects in the program shown in Listing above, the TraceHandler wrapped the actual objects.
All proxy classes override the toString, equals, and hashCode methods of the Object class. Like all proxy methods, these methods simply call invoke on the invocation handler. The other methods of the Object class (such as clone and getClass) are not redefined.
The names of proxy classes are not defined. The Proxy class in Sun’s virtual machine generates class names that begin with the string $Proxy.
There is only one proxy class for a particular class loader and ordered set of interfaces. That is, if you call the newProxyInstance method twice with the same class loader and interface array, then you get two objects of the same class. You can also obtain that class withthe getProxyClass method:
A proxy class is always public and final. If all interfaces that the proxy class implements are public, then the proxy class does not belong to any particular package. Otherwise, all non-public interfaces must belong to the same package, and then the proxy class also belongs to that package.
You can test whether a particular Class object represents a proxy class by calling the is ProxyClass method of the Proxy class.
All methods call the invoke method of the given handler object.
This ends our final section on the fundamentals of the Java programming language.
Interfaces and inner classes are concepts that you will encounter frequently. However, as we already mentioned, proxies are an advanced technique that is of interest mainly to tool builders, not application programmers. You are now ready to go on to learn about
graphics and user interfaces, starting with next section.
Core Java Related Interview Questions
|J2EE Interview Questions||Core Java Interview Questions|
|JDBC Interview Questions||JSP Interview Questions|
|Android Interview Questions||JavaServer Faces (JSF) Interview Questions|
|Java collections framework Interview Questions||Java 8 Interview Questions|
|Java Collections Interview Questions||Java Exception Handling Interview Questions|
|Java Concurrency Interview Questions||Java Serialization Interview Questions|
|Java Programmer Interview Questions||Java Inheritance Interview Questions|
|Java IO Interview Questions||Object Oriented Programming in PHP Interview Questions|
Core Java Tutorial
An Introduction To Java
The Java Programming Environment
Fundamental Programming Structures In Java
Objects And Classes
Interfaces And Inner Classes
User Interface Components With Swing
Deploying Applications And Applets
Exceptions, Logging, Assertions, And Debugging
All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd
Wisdomjobs.com is one of the best job search sites in India.