- Late Binding by Example
- Implications for Binary Compatibility
- Overloading and Overriding
- Deleting Overridden and Overloaded Methods
- Fields
- Conclusion
Overloading and Overriding
The most important thing to get out of this example is that the method match is determined by the text name of the method and the textual representation of the signature. Let's add some methods to the Sommelier class to fetch some wineglasses:
Glass fetchGlass(Wine wine)
{ ... } Glass fetchGlass(RedWine wine)
{ ... } Glass fetchGlass(WhiteWine wine)
{ ... }
When we compile the following code:
void example2() { Glass glass; Wine wine = sommelier.recommend("duck"); if(wine instanceof Bordeaux) glass = sommelier.fetchGlass((Bordeaux) wine); else glass = sommelier.fetchGlass(wine); |
there are two calls to fetchGlass; one is passed a Bordeaux object and the other a generic Wine object. The Java compiler produces two different instructions for these two calls:
invokevirtual Sommelier/fetchGlass (LRedWine;)LGlass; invokeVirtual Sommelier/fetchGlass (LWine;)LGlass;
This determination is made at compile time rather than at runtime, and it makes an important different to binary compatibility. The notation Lclassname; is how the JVM denotes a class (like the F in the previous example). These are methods that take a Wine (or a RedWine) and return a Glass.
There isn't any method on Wine that takes a Bordeaux particularly, but there is one that takes a RedWine, so that one is used in the method signature for the first call. The second call knows at compile time only that its argument is a Wine object, so that method is listed. Even if the sommelier recommends a Riesling object, it won't call the implementation of fetchGlass(whiteWine). Instead, it will use the implementation of fetchGlass(wine). Again, that's because it uses the method that exactly matches the signature.
These different definitions of fetchGlass overload rather than override each other because they have different signatures. For one method to override another, it must have the same arguments and return type. Virtual method invocation, which looks at the particular type at runtime, applies only to overridden methods (which have the same signature), not to overloaded methods (which have different signatures). Overloading is resolved at compile time. Overriding is resolved at runtime.