Granny's Programming Pearls
"inside of every large program is a small program struggling to get out"
JavaRanch.com/granny.jsp
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Attempting Polymorphism...unsuccessfully

 
Ranch Hand
Posts: 83
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm trying to write a short program to demonstrate polymorphism. Unfortunately the compiler gives me the following error when I compile my code.
TestPoly.java:63: Method setHeight(double) not found in class Circle.
cup1.setHeight(7.7);
My code is given below.

I can eliminate the error by writing a setHeight(double) method in class Circle, but a circle has no "height" so that makes no sense.
I wonder if the error is caused by declaring both my variables to be of type Circle. But I thought that by declaring the variables to be of the more general class (Circle, rather than Cylinder) the correct method would be identified by the object type.
Help! Please.
[This message has been edited by Allen Alchian (edited December 10, 2000).]
 
Greenhorn
Posts: 20
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have seen this example used in at least one book on Java. I basically disagree that Cylinder should be a sub class of Circle since a cylinder object fails the IS-A test required by inheritance. In other words, a cylinder is *not* a circle.
Although not perfect, it makes more sense to me that Cylinder should be the base class and Circle the derived class. Then height, setHeight, and getHeight would be defined in the Cylinder class and would be available to the Circle class via inhetitance. A circle object passes the IS-A test since a circle is a special case of a cylinder with a height of 0. (All Circle constructors could set height = 0, for example.)
In general, the base class should represent more general objects and the subclasses should represent more specialized objects. To me, a circle is a specialized cylinder that has height = 0.
 
Allen Alchian
Ranch Hand
Posts: 83
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the comments about Cylinders and Circles, Tom. I won't disagree about the suitability of the chosen names for this example. Perhaps I should have just used "Foo" and "Bar" or "A" and "B". But that's not the point of the question I posted.
I'm trying to understand how to successfully add and execute new methods in extended classes, which as I understand, makes the extended class more specific than the super class.
It was my understanding that by using variables of a more general class (a super class) to refer to objects of a subclass I would be able to have code execute for the subclass without having to use overridden methods. But as I continue to read my various Java books, I'm beginning to think that this concept will only work with overridden methods.
Anyone out there an expert on this??
 
Tom McQueary
Greenhorn
Posts: 20
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You are correct about the fact that what you want to do requires overridden methods. That is what I was attempting to explain but I didn't go far enough. Let me try again.
If Base is the base class, and if Base has a method foo that is overridden in a subclass, Sub, then an object of class Sub can be referred to by a Base class variable b and polymorphic behavior will result. In other words, when you call the b.foo() method and b actually contains a reference to a Sub object, then the foo method in Sub will be called.
Base b = new Sub();
b.foo(); // will call foo in the Sub class
The decision as to what foo method to call is not made until run time. The *actual* kind of object being referred to, and not the type of the reference variable, determines what foo method to call.
On the other hand, if foo is not defined in Base but is only defined in Sub, then the code above will result in a compile error since the compiler knows that there is no method foo defined in the class Base.
Another possiblilty is that class Sub does not override foo. In this case the code above still compiles. The same runtime behavior still occurs, too, but now the foo of class Sub that is being called is the foo method originally defined in Base and inherited by Sub.
Hope this helps.

 
Allen Alchian
Ranch Hand
Posts: 83
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks, Tom. You confirmed what I've been concluding: the methods must be overridden by subclasses. I had missed that point in my first reading of how to implement polymoprhism. I follow your explanation. Thanks for taking the time to walk me through it!
Allen
 
Allen Alchian
Ranch Hand
Posts: 83
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here it is, a week later, and I feel obligated to close the loop on this topic now that I've discovered the solution to my original question following additional study.
The answer I was looking for is...
The proper coding technique to avoid the compile error described in my initial posting of this thread is ...
1. First test an object variable to see what type of object it is referring to by using the "instanceof" operator.
2. Once the object type is determined, then you can call a method of that object type by casting the object variable to that object type.
With this process, the compile error is avoided and polymorphism is properly executed. And you don't have to override methods from superclasses in which the methods make no sense (such as declaring a setHeight method in a class Circle then overriding it in class Cylinder).
 
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
At a threat of re-opening the loop ......
You're quite right that the procedure you've described would work without run-time or compile-time errors. However, the point is that it isn't clean code. You're explicitly putting class-tests into your calling routine, which is exactly the situation polymorphism is designed to avoid.
For example, suppose you now added class Cone extends Circle. This is also like a circle with height, so you provide a setHeight() method to go with it.
You would now be forced to go through your system, and whenever you found your test for "instanceof Cylinder", you'd now have to add a further test for "instanceof Cone" - a long, error-prone procedure. You've lost the whole advantage of using inheritance and polymorphism.
Having to resort to these techniques is a sure sign of a design problem - in this case, should Circle be the base class in your inheritance hierarchy.
For this example, if you MUST have Circle as the base class, it would be better *** BY FAR *** to define an empty setHeight() method for Circle rather than code "instanceof" in your calling routines.
In general, really try to access an object only by the methods of your reference to that object. It really will make your life easier in the long run.
 
Rancher
Posts: 1449
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
instanceof! instanceof! That operator owes me money! (Sorry, had a flashback on the movie Stripes.)
Allen - Rob is right on the money. The use of the instanceof operator defeats the purpose of polymorphism. When you call a method the "magic" of polymorphism is supposed to figure out which method to call. So when you want polymorphic behavior in an inheritance hierarchy you must make sure you provide the signature of the method at the top of the hierarchy so that where ever in the hierarchy you are you won't get a "method not found" error.
Check out this paper on the Liskov Substitution Principle by Robert Martin. It talks about these issues.
John
 
Allen Alchian
Ranch Hand
Posts: 83
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for taking the time to post the additional comments, Rob and John.
I'll check out the paper as John suggests. At least I keep learning more and more about this stuff!
[This message has been edited by Allen Alchian (edited December 18, 2000).]
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic