Overloading, overriding and method hiding (Java)
An overview of how overloading, overriding and method hiding works in Java
Overloading
What it is: a class has several methods with the same name but different number or types of parameters and Java chooses which one to call based on the arguments you pass
class OverloadingTest {
public void testMethod(Object object) {
System.out.println("object");
}
public void testMethod(String string) {
System.out.println("string");
}
}
OverloadingTest test = new OverloadingTest();
Object testObject = new Object();
String testString = "testString";
test.testMethod(testObject); // object
test.testMethod(testString); // string
Important: the exact signature of the method to call is based at compile time using the compile-time types of the arguments
Object testStringAsObject = testString;
test.testMethod(testStringAsObject); // object
Overriding
What it is: a subclass overrides an instance method of a direct or indirect superclass by providing its own implementation
class OverridingTestSuper {
public void testMethod(Object object) {
System.out.println("super");
}
}
class OverridingTestSub extends OverridingTestSuper {
@Override
public void testMethod(Object object) {
System.out.println("sub");
}
}
Note: use@Override
annotation when overriding, so the Java compiler helps you check that the method is actually correctly overriding a supertype method
OverridingTestSuper testSuper = new OverridingTestSuper();
OverridingTestSub testSub = new OverridingTestSub();
Object testObject = new Object();
testSuper.testMethod(testObject); // super
testSub.testMethod(testObject); // sub
Important: The implementation to invoke is determined at run time based on the actual runtime type of the object and the structure of the inheritance hierarchy
OverridingTestSuper testSubAsSuper = testSub;
testSubAsSuper.testMethod(testObject); // sub
Combining overloading and overriding
class CombinedTestSuper {
public void testMethod(Object object) {
System.out.println("super object");
}
}
class CombinedTestSub extends CombinedTestSuper {
@Override
public void testMethod(Object object) {
System.out.println("sub object");
}
public void testMethod(String string) {
System.out.println("sub string");
}
}
CombinedTestSuper testSuper = new CombinedTestSuper();
CombinedTestSub testSub = new CombinedTestSub();
CombinedTestSuper testSubAsSuper = testSub;
String testString = "testString";
Object testStringAsObject = testString;
testSuper.testMethod(testString); // super object (only one method on CombinedTestSuper)
testSuper.testMethod(testStringAsObject); // super object (only one method on CombinedTestSuper)
testSub.testMethod(testString); // sub string (chooses signature testMethod(String) on CombinedTestSub)
testSub.testMethod(testStringAsObject); // sub object (chooses signature testMethod(Object) on CombinedTestSub)
testSubAsSuper.testMethod(testString); // sub object (uses signature of only method on CombinedTestSuper but implementation of CombinedTestSub)
testSubAsSuper.testMethod(testStringAsObject); // sub object (uses signature of only method on CombinedTestSuper but implementation of CombinedTestSub)
Method hiding
For static methods, overloading is still used to determine the signature of the method to invoke
But what if superclass and subclass both have static method with same signature?
class CombinedTestSuper {
public static void testStaticMethod(Object object) {
System.out.println("super");
}
}
class CombinedTestSub extends CombinedTestSuper {
public static void testStaticMethod(Object object) {
System.out.println("sub");
}
}
Calling static methods on classes:
Object testObject = new Object();
StaticSuper.testStaticMethod(testObject); // super
StaticSub.testStaticMethod(testObject); // sub
Calling static methods on instances (note that this will generate compiler warnings):
StaticSuper staticSuper = new StaticSuper();
StaticSub staticSub = new StaticSub();
StaticSuper staticSubAsSuper = staticSub;
staticSuper.testStaticMethod(testObject); // super
staticSub.testStaticMethod(testObject); // sub
staticSubAsSuper.testStaticMethod(testObject); // super (!!!)
No overriding here! Instead, we get method hiding.
Can be pretty confusing (not only the method hiding itself, but also the fact that we call a static method in a way that makes it look like an instance method), which is also why we get warnings when doing this.