Polymorphism is, generally speaking, when the same operation name does something different depending on what object it is performed on. How this decision to do something different is made is unspecified; most OOP languages do it via inheritance and so forth.
The C code I gave you is quite close to Java; just replace "const char*" with String, and instead of a pointer think of it as just an object reference.
You can write polymorphic code in Java without using inheritance -- never mind that it would be pretty silly to do so -- by using a technique similar to the above. On your objects, have a field called "object_type". The object would have a method that checked the object_type field and did something different depending on the type. (This is, again, terribly silly considering that the language gives you much better support for this kind of thing.)
Procedural programming isn't really an utterly different way of writing code that makes no sense at all to an OOP'er. The same principles for what makes good code still apply. Dikurivatives do not always have good code.