Метод может быть перегруженным, т.е. существует несколько его версий с одним и тем же именем, но с различным списком параметров. Перегрузка может ограничиваться одним классом или несколькими классами, но обязательно находящимися в одной цепочке наследования. Следует отметить, что статические методы могут перегружаться нестатическими и наоборот.
При вызове перегруженных методов следует избегать ситуаций, когда компилятор будет не в состоянии выбрать тот или иной метод, как, например, в случае:
/* пример # 5 : вызов перегруженного метода :
DemoCD.java */
class ClassC {}
class ClassD extends ClassC{}
public class DemoCD {
static void show(ClassC obj1, ClassD obj2){
System.out.println(
" первый метод show(ClassC, ClassD)");
}
static void show(ClassD obj1, ClassC obj2){
System.out.println(
" второй метод show(ClassD, ClassC)");
}
static void show(Object obj1, Object obj2){
System.out.println(
" третий метод show(Object, Object)");
}
public static void main(String[] args) {
ClassC c = new ClassC();
ClassD d = new ClassD();
Object ob= new Object();
show(c,d);//1_первый метод
show(d,c);//2_второй метод
show(c,c);//3_третий метод
//show(d,d);// 4_ошибка компиляции
show(ob, ob);//5_третий метод
show(c,ob);//6_третий метод
show(ob,d);//7_третий метод
}
}
В первом, втором и пятом случаях передаваемые параметры в метод show() полностью совпадают с параметрами при объявлении метода. В третьем случае первый и второй методы не годятся для использования, так как одним из параметров этих методов является объект класса ClassD, а определение вызываемого метода идет вверх по цепочке наследования для параметров, поэтому в данном случае будет вызван метод с параметрами типа Object. Аналогичная ситуация возникает в шестом и седьмом случаях. В четвертом случае все три метода show() одинаково подходят для вызова, поэтому возникнет ошибка компиляции. Чтобы избежать неопределенности, следует использовать явное преобразование типов, например:
show(d,(ClassC)d);
show(d,(Object)d);
Каждый из вариантов вызовет в итоге соответствующий ему метод show().
В следующем примере экземпляр подкласса создается с помощью new, ссылка на него передается объекту суперкласса. При вызове из суперкласса соответственно вызывается метод подкласса.
/* пример # 6 : динамический вызов метода :
Dispatch.java */
class A {
void myMethod() {/* private и protected использовать нельзя, так как метод при наследовании становится недоступным*/
System.out.println("метод класса А");
}
void myMethod(int i) {
System.out.println("метод класса А с аргументом");
}
}
class B extends A {
void myMethod(int i) {
System.out.println("метод класса В с аргументом");
}
}
public class C extends B {
{
System.out.println("класс C");
}
void myMethod() {
System.out.println("метод класса С");
}
}
public class Dispatch {
public static void main(String[] args) {
A obj1 = new B();
obj1.myMethod();
A obj2 = new C();
obj2.myMethod();
obj2.myMethod(10);
}
}
В результате будет выведено:
метод класса А
класс C
метод класса С
метод класса В с аргументом
При первом обращении вызывается метод myMethod() из класса A как унаследованный. При втором обращении вызывается метод myMethod() из класса C как переопределенный. В последнем случае вызывается метод myMethod(int i) из класса B как унаследованный.