http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html

<html>
<head>
<meta name="collection" content="reference"><title>Dynamic Proxy Classes
</title></head>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#000077" ALINK="#FF0000">

<TABLE BORDER="0" WIDTH="100%">
<TR>
<TD WIDTH="60">
   <IMG SRC="../../images/javalogo52x88.gif" ALT="Java" BORDER=0 WIDTH=52 HEIGHT
=88>
</TD>

<TD>
<center>
           <h1>Dynamic Proxy Classes</h1>
</center>
</TD>


<TD ALIGN=RIGHT VALIGN=TOP>
   <font size="-1"><a href="../../index.html">Documentation Contents</a></font>
</TD>
</TR>
</TABLE>

<!-- ====================== Body text begins here ====================== -->

<h2>Contents</h2>
<blockquote><strong>
<a href=#intro>Introduction</a><br>
<a href=#api>Dynamic Proxy API</a><br>
<a href=#serial>Serialization</a><br>
<a href=#examples>Examples</a>
</strong></blockquote>

<a name=intro>
<h2>Introduction</h2></a>
<blockquote>
<p>A <i>dynamic proxy class</i> is a class that implements a list of
interfaces specified at runtime such that a method invocation through
one of the interfaces on an instance of the class will be encoded and
dispatched to another object through a uniform interface.  Thus, a
dynamic proxy class can be used to create a type-safe proxy object for
a list of interfaces without requiring pre-generation of the proxy
class, such as with compile-time tools.  Method invocations on an
instance of a dynamic proxy class are dispatched to a single method in
the instance's <i>invocation handler</i>, and they are encoded with a
<code>java.lang.reflect.Method</code> object identifying the method
that was invoked and an array of type <code>Object</code> containing
the arguments.

<p>Dynamic proxy classes are useful to an application or library that
needs to provide type-safe reflective dispatch of invocations on
objects that present interface APIs.  For example, an application can
use a dynamic proxy class to create an object that implements multiple
arbitrary event listener interfaces-- interfaces that extend
<code>java.util.EventListener</code>-- to process a variety of events
of different types in a uniform fashion, such as by logging all such
events to a file.
</blockquote>
<p>

<a name=api>
<h2>Dynamic Proxy Class API
</h2></a>
<blockquote>
<p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
class</i> below) is a class that implements a list of interfaces
specified at runtime when the class is created.

<p>A <i>proxy interface</i> is such an interface that is implemented
by a proxy class.

<p>A <i>proxy instance</i> is an instance of a <i>proxy class</i>.

<h3>Creating a Proxy Class
</h3>

<p>Proxy classes, as well as instances of them, are created using the
static methods of the class <tt><a href=../../api/java/lang/reflect/Proxy.html>java.lang.reflect.Proxy</a></tt>.



<p>The <code>Proxy.getProxyClass</code> method returns the
<code>java.lang.Class</code> object for a proxy class given a class
loader and an array of interfaces.  The proxy class will be defined in
the specified class loader and will implement all of the supplied
interfaces.  If a proxy class for the same permutation of interfaces
has already been defined in the class loader, then the existing proxy
class will be returned; otherwise, a proxy class for those interfaces
will be generated dynamically and defined in the class loader.

<p>There are several restrictions on the parameters that may be passed
to <code>Proxy.getProxyClass</code>:

<ul>

<li>All of the <code>Class</code> objects in the <code>interfaces</code>
array must represent interfaces, not classes or primitive types.

<li>No two elements in the <code>interfaces</code> array may refer to
identical <code>Class</code> objects.

<li>All of the interface types must be visible by name through the
specified class loader.  In other words, for class loader
<code>cl</code> and every interface <code>i</code>, the following
expression must be true:

<pre>
	Class.forName(i.getName(), false, cl) == i
</pre>

<li>All non-public interfaces must be in the same package; otherwise,
it would not be possible for the proxy class to implement all of the
interfaces, regardless of what package it is defined in.

<li>No two interfaces may each have a method with the same name and
parameter signature but different return type.

<li>The resulting proxy class must not exceed any limits imposed on
classes by the virtual machine.  For example, the VM may limit the
number of interfaces that a class may implement to 65535; in that
case, the size of the <code>interfaces</code> array must not exceed
65535.

</ul>

<p>If any of these restrictions are violated,
<code>Proxy.getProxyClass</code> will throw an
<code>IllegalArgumentException</code>.  If the <code>interfaces</code>
array argument or any of its elements are <code>null</code>, a
<code>NullPointerException</code> will be thrown.

<p>Note that the order of the specified proxy interfaces is
significant: two requests for a proxy class with the same combination
of interfaces but in a different order will result in two distinct
proxy classes.  Proxy classes are distinguished by the order of their
proxy interfaces in order to provide deterministic method invocation
encoding in cases where two or more of the proxy interfaces share a
method with the same name and parameter signature; this reasoning is
described in more detail in the section below titled 
<a href=#methods><b>Methods Duplicated in Multiple Proxy Interfaces</b></a>.

<p>So that a new proxy class does not need to be generated each time
<code>Proxy.getProxyClass</code> is invoked with the same class loader
and list of interfaces, the implementation of the dynamic proxy class
API should keep a cache of generated proxy classes, keyed by their
corresponding loaders and interface list.  The implementation should
be careful not to refer to the class loaders, interfaces, and proxy
classes in such a way as to prevent class loaders, and all of their
classes, from being garbage collected when appropriate.

<h3>Proxy Class Properties
</h3>

<p>A proxy class has the following properties:

<ul>

<li>Proxy classes are public, final, and not abstract.

<li>The unqualified name of a proxy class is unspecified.  The space
of class names that begin with the string <code>"$Proxy"</code> is,
however, to be reserved for proxy classes.

<li>A proxy class extends <code><a href=../../api/java/lang/reflect/Proxy.html>java.lang.reflect.Proxy</a></code>.

<li>A proxy class implements exactly the interfaces specified at its
creation, in the same order.

<li>If a proxy class implements a non-public interface, then it will
be defined in the same package as that interface.  Otherwise, the
package of a proxy class is also unspecified.  Note that package
sealing will not prevent a proxy class from being successfully defined
in a particular package at runtime, and neither will classes already
defined in the same class loader and the same package with particular
signers.

<li>Since a proxy class implements all of the interfaces specified at
its creation, invoking <code>getInterfaces</code> on its
<code>Class</code> object will return an array containing the same
list of interfaces (in the order specified at its creation), invoking
<code>getMethods</code> on its <code>Class</code> object will return
an array of <code>Method</code> objects that include all of the
methods in those interfaces, and invoking <code>getMethod</code> will
find methods in the proxy interfaces as would be expected.

<li>The <code>Proxy.isProxyClass</code> method will return true if it
is passed a proxy class-- a class returned by
<code>Proxy.getProxyClass</code> or the class of an object returned by
<code>Proxy.newProxyInstance</code>-- and false otherwise.  The
reliability of this method is important for the ability to use it to
make security decisions, so its implementation should not just test if
the class in question extends <code>java.lang.reflect.Proxy</code>.

<li>The <code>java.security.ProtectionDomain</code> of a proxy class
is the same as that of system classes loaded by the bootstrap class
loader, such as <code>java.lang.Object</code>, because the code for a
proxy class is generated by trusted system code.  This protection
domain will typically be granted
<code>java.security.AllPermission</code>.

</ul>

<h3> Creating a Proxy Instance
</h3>

<p>Each proxy class has one public constructor that takes one argument,
an implementation of the interface 
<code><a href="../../api/java/lang/reflect/InvocationHandler.html">InvocationHandler</a></code>.

<p>Each proxy instance has an associated invocation handler object,
the one that was passed to its constructor.  Rather than having to use
the reflection API to access the public constructor, a proxy instance
can be also be created by calling the
<code>Proxy.newProxyInstance</code> method, which combines the actions
of calling <code>Proxy.getProxyClass</code> with invoking the
constructor with an invocation handler.
<code>Proxy.newProxyInstance</code> throws
<code>IllegalArgumentException</code> for the same reasons that
<code>Proxy.getProxyClass</code> does.

<h3> Proxy Instance Properties
</h3>

<p>A proxy instance has the following properties:

<ul>

<li>Given a proxy instance <code>proxy</code> and one of the
interfaces implemented by its proxy class <code>Foo</code>, the
following expression will return true:

<pre>
	<code>proxy instanceof Foo</code>
</pre>

and the following cast operation will succeed (rather than throwing
a <code>ClassCastException</code>):

<pre>
	<code>(Foo) proxy</code>
</pre>

<p><li>The static <code>Proxy.getInvocationHandler</code> method will
return the invocation handler associated with the proxy instance
passed as its argument.  If the object passed to
<code>Proxy.getInvocationHandler</code> is not a proxy instance, then
an <code>IllegalArgumentException</code> will be thrown.

<p><li>An interface method invocation on a proxy instance will be
encoded and dispatched to the invocation handler's <code>invoke</code>
method as described below.

<p>The proxy instance itself will be passed as the first argument of
<code>invoke</code>, which is of type <code>Object</code>.

<p>The second argument passed to <code>invoke</code> will be the
<code>java.lang.reflect.Method</code> instance corresponding to the
interface method invoked on the proxy instance.  The declaring class
of the <code>Method</code> object will be the interface that the
method was declared in, which may be a superinterface of the proxy
interface that the proxy class inherits the method through.

<p>The third argument passed to <code>invoke</code> will be an array
of objects containing the values of the arguments passed in the method
invocation on the proxy instance.  Arguments of primitive types are
wrapped in an instance of the appropriate primitive wrapper class,
such as <code>java.lang.Integer</code> or
<code>java.lang.Boolean</code>.  The implementation of the
<code>invoke</code> method is free to modify the contents of this
array.

<p>The value returned by the <code>invoke</code> method will become
the return value of the method invocation on the proxy instance.  If
the declared return value of the interface method is a primitive type,
then the value returned by <code>invoke</code> must be an instance of
the corresponding primitive wrapper class; otherwise, it must be a
type assignable to the declared return type.  If the value returned by
<code>invoke</code> is <code>null</code> and the interface method's
return type is primitive, then a <code>NullPointerException</code>
will be thrown by the method invocation on the proxy instance.  If the
value returned by <code>invoke</code> is otherwise not compatible with
the method's declared return type as described above, a
<code>ClassCastException</code> will be thrown by the proxy instance.

<p>If an exception is thrown by the <code>invoke</code> method, it
will be also thrown by the method invocation on the proxy instance.
The exception's type must be assignable to either any of the exception
types declared in the signature of the interface method or to the
unchecked exception types <code>java.lang.RuntimeException</code> or
<code>java.lang.Error</code>.  If a checked exception is thrown by
<code>invoke</code> that is not assignable to any of the exception
types declared in the <code>throws</code> clause of the interface
method, then an 
<code><a href="../../api/java/lang/reflect/UndeclaredThrowableException.html">UndeclaredThrowableException</a></code> will be
thrown by the method invocation on the proxy instance. 
The <code>UndeclaredThrowableException</code> will be constructed with
the exception that was thrown by the <code>invoke</code> method.

<p><li>An invocation of the <code>hashCode</code>,
<code>equals</code>, or <code>toString</code> methods declared in
<code>java.lang.Object</code> on a proxy instance will be encoded and
dispatched to the invocation handler's <code>invoke</code> method in
the same manner as interface method invocations are encoded and
dispatched, as described above.  The declaring class of the
<code>Method</code> object passed to <code>invoke</code> will be
<code>java.lang.Object</code>.  Other public methods of a proxy
instance inherited from <code>java.lang.Object</code> are not
overridden by a proxy class, so invocations of those methods behave
like they do for instances of <code>java.lang.Object</code>.

</ul>
<a name=methods>
<h3>Methods Duplicated in Multiple Proxy Interfaces
</h3></a>

<p>When two or more interfaces of a proxy class contain a method with
the same name and parameter signature, the order of the proxy class's
interfaces becomes significant.  When such a <i>duplicate method</i>
is invoked on a proxy instance, the <code>Method</code> object passed
to the invocation handler will not necessarily be the one whose
declaring class is assignable from the reference type of the interface
that the proxy's method was invoked through.  This limitation exists
because the corresponding method implementation in the generated proxy
class cannot determine which interface it was invoked through.
Therefore, when a duplicate method is invoked on a proxy instance, the
<code>Method</code> object for the method in the foremost interface
that contains the method (either directly or inherited through a
superinterface) in the proxy class's list of interfaces is passed to
the invocation handler's <code>invoke</code> method, regardless of the
reference type through which the method invocation occurred.

<p>If a proxy interface contains a method with the same name and
parameter signature as the <code>hashCode</code>, <code>equals</code>,
or <code>toString</code> methods of <code>java.lang.Object</code>,
when such a method is invoked on a proxy instance, the
<code>Method</code> object passed to the invocation handler will have
<code>java.lang.Object</code> as its declaring class.  In other words,
the public, non-final methods of <code>java.lang.Object</code>
logically precede all of the proxy interfaces for the determination of
which <code>Method</code> object to pass to the invocation handler.

<p>Note also that when a duplicate method is dispatched to an
invocation handler, the <code>invoke</code> method may only throw
checked exception types that are assignable to one of the exception
types in the <code>throws</code> clause of the method in <i>all</i> of
the proxy interfaces that it can be invoked through.  If the
<code>invoke</code> method throws a checked exception that is not
assignable to any of the exception types declared by the method in one
of the the proxy interfaces that it can be invoked through, then an
unchecked <code>UndeclaredThrowableException</code> will be thrown by
the invocation on the proxy instance.  This restriction means that not
all of the exception types returned by invoking
<code>getExceptionTypes</code> on the <code>Method</code> object
passed to the <code>invoke</code> method can necessarily be thrown
successfully by the <code>invoke</code> method.
</blockquote>

<a name=serial>
<h2>Serialization
</h2></a>
<blockquote>
<p>Since <code>java.lang.reflect.Proxy</code> implements
<code>java.io.Serializable</code>, proxy instances can be serialized,
as described in this section.  If a proxy instance contains an
invocation handler that is not assignable to
<code>java.io.Serializable</code>, however, then a
<code>java.io.NotSerializableException</code> will be thrown if such
an instance is written to a <code>java.io.ObjectOutputStream</code>.
Note that for proxy classes, implementing
<code>java.io.Externalizable</code> has the same effect with respect
to serialization as implementing <code>java.io.Serializable</code>:
the <code>writeExternal</code> and <code>readExternal</code> methods
of the <code>Externalizable</code> interface will never be invoked on
a proxy instance (or an invocation handler) as part of its
serialization process.  As with all <code>Class</code> objects, the
<code>Class</code> object for a proxy class is always serializable.


<p>A proxy class has no serializable fields and a
<code>serialVersionUID</code> of <code>0L</code>.  In other words,
when the <code>Class</code> object for a proxy class is passed to the
static <code>lookup</code> method of
<code>java.io.ObjectStreamClass</code>, the returned
<code>ObjectStreamClass</code> instance will have the following
properties:

<ul>

<li>Invoking its <code>getSerialVersionUID</code> method will return
<code>0L</code>.

<li>Invoking its <code>getFields</code> method will return an array
of length zero.

<li>Invoking its <code>getField</code> method with any
<code>String</code> argument will return <code>null</code>.

</ul>

<p>The stream protocol for Object Serialization supports a type code
named <code>TC_PROXYCLASSDESC</code>, which is a terminal symbol in
the grammar for the stream format; its type and value are defined by
the following constant field in the
<code>java.io.ObjectStreamConstants</code> interface:

<pre>
    final static byte TC_PROXYCLASSDESC = (byte)0x7D;
</pre>

<p>The grammar also includes the following two rules, the first being
an alternate expansion of the original <i>newClassDesc</i> rule:

<p><i>newClassDesc</i>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>TC_PROXYCLASSDESC</code> <i>newHandle</i> <i>proxyClassDescInfo</i>
<p><i>proxyClassDescInfo</i>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>(int)&lt;count&gt;</code> <i>proxyInterfaceName[count]</i> <i>classAnnotation</i> <i>superClassDesc</i>
<p><i>proxyInterfaceName</i>:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>(utf)</code>

<p>When an <code>ObjectOutputStream</code> serializes the class
descriptor for a class that is a proxy class, as determined by passing
its <code>Class</code> object to the <code>Proxy.isProxyClass</code>
method, it uses the <code>TC_PROXYCLASSDESC</code> type code instead
of <code>TC_CLASSDESC</code>, following the rules above.  In the
expansion of <i>proxyClassDescInfo</i>, the sequence of
<i>proxyInterfaceName</i> items are the names of all of the interfaces
implemented by the proxy class, in the order that they are returned by
invoking the <code>getInterfaces</code> method on the
<code>Class</code> object.  The <i>classAnnotation</i> and
<i>superClassDesc</i> items have the same meaning as they do in the
<i>classDescInfo</i> rule.  For a proxy class, <i>superClassDesc</i>
is the class descriptor for its superclass,
<code>java.lang.reflect.Proxy</code>; including this descriptor allows
for the evolution of the serialized representation of the class
<code>Proxy</code> for proxy instances.

<p>For non-proxy classes, <code>ObjectOutputStream</code> calls its
protected <code>annotateClass</code> method to allow subclasses to
write custom data to the stream for a particular class.  For proxy
classes, instead of <code>annotateClass</code>, the following method
in <code>java.io.ObjectOutputStream</code> is called with the
<code>Class</code> object for the proxy class:

<pre>
    protected void annotateProxyClass(Class cl) throws IOException;
</pre>

<p>The default implementation of <code>annotateProxyClass</code> in
<code>ObjectOutputStream</code> does nothing.

<p>When an <code>ObjectInputStream</code> encounters the type code
<code>TC_PROXYCLASSDESC</code>, it deserializes the class descriptor
for a proxy class from the stream, formatted as described above.
Instead of calling its <code>resolveClass</code> method to resolve the
<code>Class</code> object for the class descriptor, the following
method in <code>java.io.ObjectInputStream</code> is called:

<pre>
    protected Class resolveProxyClass(String[] interfaces)
	throws IOException, ClassNotFoundException;
</pre>

<p>The list of interface names that were deserialized in the proxy
class descriptor are passed as the <code>interfaces</code> argument to
<code>resolveProxyClass</code>.

<p>The default implementation of <code>resolveProxyClass</code> in
<code>ObjectInputStream</code> returns the results of calling
<code>Proxy.getProxyClass</code> with the list of <code>Class</code>
objects for the interfaces named in the <code>interfaces</code>
parameter.  The <code>Class</code> object used for each interface name
<code>i</code> is the value retuned by calling

<pre>
	Class.forName(i, false, loader)
</pre>

where <code>loader</code> is the first non-null class loader up the
execution stack, or <code>null</code> if no non-null class loaders are
on the stack.  This is the same class loader choice made by the
default behavior of the <code>resolveClass</code> method.  This same
value of <code>loader</code> is also the class loader passed to
<code>Proxy.getProxyClass</code>.  If <code>Proxy.getProxyClass</code>
throws an <code>IllegalArgumentException</code>,
<code>resolveClass</code> will throw a
<code>ClassNotFoundException</code> containing the
<code>IllegalArgumentException</code>.

<p>Since a proxy class never has its own serializable fields, the
<i>classdata[]</i> in the stream representation of a proxy instance
consists wholly of the instance data for its superclass,
<code>java.lang.reflect.Proxy</code>.  <code>Proxy</code> has one
serializable field, <code>h</code>, which contains the invocation
handler for the proxy instance.
</blockquote>

<a name=examples>
<h2>Examples
</h2></a>
<blockquote>
<p>Here is a simple example that prints out a message before and after
a method invocation on an object that implements an arbitrary list of
interfaces:

<pre>
public interface Foo {
    Object bar(Object obj) throws BazException;
}

public class FooImpl implements Foo {
    Object bar(Object obj) throws BazException {
        // ...
    }
}

public class DebugProxy implements java.lang.reflect.InvocationHandler {

    private Object obj;

    public static Object newInstance(Object obj) {
	return java.lang.reflect.Proxy.newProxyInstance(
	    obj.getClass().getClassLoader(),
	    obj.getClass().getInterfaces(),
	    new DebugProxy(obj));
    }

    private DebugProxy(Object obj) {
	this.obj = obj;
    }

    public Object invoke(Object proxy, Method m, Object[] args)
	throws Throwable
    {
        Object result;
	try {
	    System.out.println("before method " + m.getName());
	    result = m.invoke(obj, args);
        } catch (InvocationTargetException e) {
	    throw e.getTargetException();
        } catch (Exception e) {
	    throw new RuntimeException("unexpected invocation exception: " +
				       e.getMessage());
	} finally {
	    System.out.println("after method " + m.getName());
	}
	return result;
    }
}
</pre>

<p>To construct a <code>DebugProxy</code> for an implementation of the
<code>Foo</code> interface and call one of its methods:

<pre>
    Foo foo = (Foo) DebugProxy.newInstance(new FooImpl());
    foo.bar(null);
</pre>

<p>Here is an example of a utility invocation handler class that
provides default proxy behavior for methods inherited from
<code>java.lang.Object</code> and implements delegation of certain
proxy method invocations to distinct objects depending on the
interface of the invoked method:

<pre>
import java.lang.reflect.*;

public class Delegator implements InvocationHandler {

    // preloaded Method objects for the methods in java.lang.Object
    private static Method hashCodeMethod;
    private static Method equalsMethod;
    private static Method toStringMethod;
    static {
	try {
	    hashCodeMethod = Object.class.getMethod("hashCode", null);
	    equalsMethod =
		Object.class.getMethod("equals", new Class[] { Object.class });
	    toStringMethod = Object.class.getMethod("toString", null);
        } catch (NoSuchMethodException e) {
	    throw new NoSuchMethodError(e.getMessage());
	}
    }

    private Class[] interfaces;
    private Object[] delegates;

    public Delegator(Class[] interfaces, Object[] delegates) {
	this.interfaces = (Class[]) interfaces.clone();
	this.delegates = (Object[]) delegates.clone();
    }

    public Object invoke(Object proxy, Method m, Object[] args)
	throws Throwable
    {
	Class declaringClass = m.getDeclaringClass();

	if (declaringClass == Object.class) {
	    if (m.equals(hashCodeMethod)) {
		return proxyHashCode(proxy);
	    } else if (m.equals(equalsMethod)) {
		return proxyEquals(proxy, args[0]);
	    } else if (m.equals(toStringMethod)) {
		return proxyToString(proxy);
	    } else {
		throw new InternalError(
		    "unexpected Object method dispatched: " + m);
	    }
	} else {
	    for (int i = 0; i < interfaces.length; i++) {
		if (declaringClass.isAssignableFrom(interfaces[i])) {
		    try {
			return m.invoke(delegates[i], args);
		    } catch (InvocationTargetException e) {
			throw e.getTargetException();
		    }
		}
	    }

	    return invokeNotDelegated(proxy, m, args);
	}
    }

    protected Object invokeNotDelegated(Object proxy, Method m,
				        Object[] args)
	throws Throwable
    {
	throw new InternalError("unexpected method dispatched: " + m);
    }

    protected Integer proxyHashCode(Object proxy) {
	return new Integer(System.identityHashCode(proxy));
    }

    protected Boolean proxyEquals(Object proxy, Object other) {
	return (proxy == other ? Boolean.TRUE : Boolean.FALSE);
    }

    protected String proxyToString(Object proxy) {
	return proxy.getClass().getName() + '@' +
	    Integer.toHexString(proxy.hashCode());
    }
}
</pre>

<p>Subclasses of <code>Delegator</code> can override
<code>invokeNotDelegated</code> to implement the behavior of proxy
method invocations not to be directly delegated to other objects, and
they can override <code>proxyHashCode</code>,
<code>proxyEquals</code>, and <code>proxyToString</code> to override
the default behavior of the methods the proxy inherits from
<code>java.lang.Object</code>.

<p>To construct a <code>Delegator</code> for an implementation of the
<code>Foo</code> interface:

<pre>
    Class[] proxyInterfaces = new Class[] { Foo.class };
    Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
	proxyInterfaces,
	new Delegator(proxyInterfaces, new Object[] { new FooImpl() }));
</pre>

<p>Note that the implementation of the <code>Delegator</code> class
given above is intended to be more illustrative than optimized; for
example, instead of caching and comparing the <code>Method</code>
objects for the <code>hashCode</code>, <code>equals</code>, and
<code>toString</code> methods, it could just match them by their
string names, because none of those method names are overloaded in
<code>java.lang.Object</code>.

</blockquote>
<br><HR SIZE=3 NOSHADE>

<TABLE BORDER="0" WIDTH="100%">
<TR VALIGN=TOP>

<TD>
<FONT SIZE="-2">
   <A HREF="../../relnotes/SMICopyright.html">Copyright</A> &#169; 1999
   <A HREF="http://www.sun.com/">Sun Microsystems, Inc.</A>
    All Rights Reserved.</FONT>
   <br>
   <br>

   <FONT SIZE="-1">
   Please send comments to: <a href="mailto:reflection-comments@eng.sun.com">reflect
ion-comments@sun.com</a>
   </FONT>

</TD>

<TD ALIGN=RIGHT>
   <IMG SRC="../../images/sunlogo64x30.gif" ALT="Sun" BORDER=0 WIDTH=64 HEIGHT=30>
   <BR>
   <BR>
   <FONT SIZE="+1">
   <i>Java Software</i>
   </FONT>
</TD>

</TR>
</TABLE>

</body>
<script language="JavaScript" src="/js/omi/jsc/s_code_remote.js"></script></html>
