Article View: borland.public.jbuilder.java.language
Article #17860Re: Double dispatching technique (Visitor pattern)
From: John P. McGrath
Date: Mon, 14 Sep 1998 00:00
Date: Mon, 14 Sep 1998 00:00
167 lines
5345 bytes
5345 bytes
Edoardo:
The behavior you are seeing is the correct behavior.
When the compiler compiles a method call, it determines the signature of
the method to be called, based on the types of the arguments specified in
the call, and stores the method signature in the class file. So these
lines of code generate the method calls in the comments.
1) // Call print(Fruit) on a Main object.
Fruit fruit = new Fruit();
print(fruit);
2) // Call print(Apple) on a Main object.
Apple apple = new Apple();
print(apple);
3) // Call print(Fruit) on a Main object.
Fruit fruit2 = new Apple();
print(fruit2);
4) // Call print() on a Fruit object.
void print(Fruit aFruit) {
aFruit.print();
}
5) // Call print() on an Apple object.
void print(Apple anApple) {
anApple.print();
}
When the JVM interprets these method calls, it calls the method with the
specified signature for the run-time object whose method is being called.
In cases 1, 2, and 3, the object is a Main object. In case 5, the object
is an Apple object. Since there are no subclasses of Main and Apple, it
is obvious which is called. Of course, this assumes that there are no
other classes involved that extend Main or Apple.
In case 4, however, the class of the object receiving the print() call
could be either a Fruit or of a sub-class of Fruit (i.e. Apple). The
method being called depends on the object receiving the method call. So
this could call either Fruit.print() or Apple.print(). But no matter
what type of object is having its method invoked, we know at compile time
that the print() method will be called. The signature of the method to
be called was determined at compile time.
So the short answer is, Java does not directly support the double
dispatch that you are looking for. If you want to, you can implement
double dispatching using the Reflection mechanism. You would have to
look up all of the available methods for the target object and all of its
superclasses, and determine which method matched your call best.
In a simple case, such as your example code, this might be relatively
easy. But lets make it just a little more complicated. What if there
were more than one argument? Say you had the following call:
eat( new Apple(), new Apple() );
... and the target object had two print methods:
eat( Apple apple, Fruit fruit );
eat( Fruit fruit, Apple apple );
Which method would you want to be called in this case?
Also consider the additional run-time overhead that would be required on
every method call in order to support double dispatch. It would slow
down all Java programs, not just those that used the facility.
--
Regards,
John P. McGrath
<mcgrath@enter.net>
<jpm@nscs.fast.net>
Edoardo Comar <comar@tecnest.it> wrote:
> Does the double dispatching technique of GOF's Visitor pattern not always
> work in Java ?
>
> I saw that if you have an overloaded method of which a version take as an
> argument an object of class A,
> and another takes an object of class B which extends A, if you invoke it
> with a reference of type A which points to
> a class B object, the JVM selects the first version (the one which declares
> an instance of class A as its parameter).
>
> Is this behavior correct ?
>
> If you like, play with this sample of mine.
> =======
> package edotest;
>
> public class Fruit
> {
> public void print() // (3)
> {
> System.out.println("Fruit");
> }
> }
> =======
> package edotest;
>
> public class Apple extends Fruit
> {
> public void print() // (4)
> {
> System.out.println("Apple");
> }
> }
> =======
> package edotest;
>
> public class Main
> {
> Fruit fruit = new Fruit();
> Apple apple = new Apple();
> Fruit fruit2 = new Apple();
>
> public static void main(String[] args)
> {
> Main main = new Main();
> main.test();
> }
>
>
> void test()
> {
> print(fruit); // invokes (1 + 3 )
> print(apple); // invokes (2+ 4 )
> print(fruit2); // invokes (1 + 4 )
> }
>
>
> void print(Fruit aFruit) // (1)
> {
> System.out.print("Main.print(Fruit aFruit) : ");
> aFruit.print();
> }
>
>
> void print(Apple anApple) // (2)
> {
> System.out.print("Main.print(Apple anApple) : ");
> anApple.print();
> }
>
> }
> =======
>
>
> bye,
> Edo.
>
> ing. Edoardo Comar
> <comar@tecnest.it>
> Tecnest S.r.l
> via Tullio, 11/13 - 33100 Udine Italy
> ph. +39 432 511550
> fax +39 432 508725
> --------
> <e.comar@go.nettuno.it> (home email)
> PGP RSA key on keyservers http://wwwkeys.pgp.net
> key ID 29365395 created 1994/11/03
> fingerprint = 5E 10 E1 46 22 35 84 3D 3F 57 E0 35 BE 5C 1E A7
Technical Details
Message-ID:
<MPG.106681ecc7d3db84989695@forums.inprise.com>Path:
arc1-ca.pugleaf.net!unknown!not-for-mailReferences:
<6sjh8m$eq419@forums.borland.com>Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: f74b3,107ec690fdf39b4a X-Google-Attributes: gidf74b3,public From: mcgrath@enter.net (John P. McGrath) Subject: Re: Double dispatching technique (Visitor pattern) Date: 1998/09/14 Message-ID: <MPG.106681ecc7d3db84989695@forums.inprise.com> X-Deja-AN: 390902607 References: <6sjh8m$eq419@forums.borland.com> Organization: Software Consulting Services Newsgroups: borland.public.jbuilder.java.language