-
L'outrepassement des méthodes est possible uniquement pour les méthodes qui sont héritables.
Par exemple, une méthode marquée private
n'est pas héritable et ne peut pas donc être outrepassée.
Mais rien n'empêche de fournir une implémentation de la même méthode avec le même nom, la même signature (paramètres), et le même type de retour dans la sous-classe,
mais dans ce cas c'est comme si on a créé une nouvelle méthode qui n'a absolument rien avoir avec la méthode de superclasse.
-
Une sous-classe dans le même package que celui de la superclasse peut outrepasser toutes les méthodes de cette classe qui ne sont pas marquées
private
.
-
Une sous-classe dans un package différent de celui de la superclasse peut outrepasser toutes les méthodes de cette classe qui sont marquées
public
ou protected
.
-
On ne peut pas outrepasser une méthode marquée
final
.
Le compilateur affichera un message d'erreur : "Cannot override the final method from SuperClass"
public class SuperClass {
public final Integer subtractOperation(Integer value1, Integer value2) {
return (value1 - value2);
}
}
public class SubClass extends SuperClass {
public Integer subtractOperation(Integer value1, Integer value2) { // compiler error: Cannot override the final method from SuperClass
return (value1 - value2) * 10;
}
}
-
On ne peut pas outrepasser une méthode marquée
static
.
Le compilateur affichera un message d'erreur : "This instance method cannot override the static method from SuperClass"
public class SuperClass {
public static Integer subtractOperation(Integer value1, Integer value2) {
return (value1 - value2);
}
}
public class SubClass extends SuperClass {
public Integer subtractOperation(Integer value1, Integer value2) { // compiler error: This instance method cannot override the static method from SuperClass
return (value1 - value2) * 10;
}
}
Cependant, il est correcte de marquer static
la méthode de la sous-classe ; dans ce cas il s'agit d'une nouvelle méthode qui n'a aucune relation avec la méthode de la superclasse.
Dans ce cas, la version de la méthode invoquée dépendra du type de la variable (définie dans sa déclaration) et non pas de l'instance en mémoire.
public class SubClass extends SuperClass {
public static Integer subtractOperation(Integer value1, Integer value2) {
return (value1 - value2) * 10;
}
}
public class TestClass {
public static void main(String[] args) {
SuperClass superClass1 = new SuperClass();
SuperClass superClass2 = new SubClass();
SubClass subClass1 = new SubClass();
System.out.println(superClass1.subtractOperation(5, 2)); // affiche 3 : utilise la version de la méthode de la classe SuperClass
System.out.println(superClass2.subtractOperation(5, 2)); // affiche 3 : utilise la version de la méthode de la classe SuperClass
System.out.println(subClass1.subtractOperation(5, 2)); // affiche 30 : utilise la version de la méthode de la classe SubClass
System.out.println();
System.out.println(SuperClass.subtractOperation(5, 2)); // affiche 3 : utilise la version de la méthode de la classe SuperClass
System.out.println(SubClass.subtractOperation(5, 2)); // affiche 30 : utilise la version de la méthode de la classe SubClass
}
}
-
Pour être considéré comme une méthode outrepassante, la liste des paramètres doit correspondre exactement à celle de la méthode de la superclasse.
Le type de chaque paramètre de la version de la méthode de la sous-classe doit être le même que celui du paramètre correspondant de la version de la méthode de la superclasse.
Si le nombre des paramètres est différent dans les deux versions ou que les types des paramètres sont différents (un sous-type est considéré comme différent),
alors il ne s'agit pas d'un outrepassement mais de deux méthodes complètement différentes.
public class SuperClass {
public void doSomeThing(SuperClass superClass) { }
}
public class SubClass extends SuperClass {
public void doSomeThing(SuperClass superClass) { } // outrepassement
public void doSomeThing(SubClass subClass) { } // nouvelle méthode
public void doSomeThing(SubClass subClass1, SubClass subClass2) { } // nouvelle méthode
}
Le détail de la surcharge des méthodes sera discuté dans une page séparée (Surcharge de méthode (method overloading)),
mais il faut juste noter maintenant que la résolution de la méthode qui sera exécutée dépendra des types des arguments.
public class TestClass {
public static void main(String[] args) {
SuperClass superClass1 = new SuperClass();
SuperClass superClass2 = new SubClass();
SubClass subClass1 = new SubClass();
superClass1.doSomeThing(superClass1); // la version de la méthode de la superclasse (SuperClass) sera exécutée : public void doSomeThing(SuperClass superClass)
superClass1.doSomeThing(subClass1); // la version de la méthode de la superclasse (SuperClass) sera exécutée : public void doSomeThing(SuperClass superClass)
superClass2.doSomeThing(superClass1); // la version de la méthode de la sous-classe (SubClass) sera exécutée : public void doSomeThing(SuperClass superClass)
superClass2.doSomeThing(subClass1); // la version de la méthode de la sous-classe (SubClass) sera exécutée : public void doSomeThing(SuperClass superClass)
subClass1.doSomeThing(superClass1); // la version de la méthode de la sous-classe (SubClass) sera exécutée : public void doSomeThing(SuperClass superClass)
subClass1.doSomeThing(subClass1); // la nouvelle méthode de la sous-classe (SubClass) sera exécutée : public void doSomeThing(SubClass subClass)
subClass1.doSomeThing(subClass1, subClass1); // la nouvelle méthode de la sous-classe (SubClass) sera exécutée : public void doSomeThing(SubClass subClass1, SubClass subClass2)
}
}
-
Le type de retour de la méthode outrepassante doit être du même type ou un sous-type de celui de la méthode de la superclasse.
Si le type de retour est différent, alors le compilateur affichera une erreur.
public class SuperClass {
public SuperClass doSomeThing() { return null; }
}
public class SubClass extends SuperClass {
public Object doSomeThing() { return null; } // compiler error: The return type is incompatible with SuperClass.doSomeThing()
}
Pour corriger le code de l'exemple précédent, il faut modifier le type de retour en SuperClass
ou SubClass
.
Il faut noter, cependant, que si le nombre des paramètres est différent dans les deux versions des méthodes de la superclasse et la sous-classe
ou que les types des paramètres sont différents (un sous-type est considéré comme différent),
alors cette règle ne s'applique pas vu qu'il ne s'agit pas d'un outrepassement.
-
La visibilité (modificateur d'accès) de la méthode outrepassante ne peut pas être plus restrictive que la méthode de la superclasse.
Par exemple : on ne peut pas outrepasser une méthode declarée public
et la déclarer protected
ou private
:
public class SuperClass {
public void doSomeThing() { }
}
public class SubClass extends SuperClass {
protected void doSomeThing() { } // compiler error: Cannot reduce the visibility of the inherited method from SuperClass
}
-
La visibilité de la méthode outrepassante peut être moins restrictive que la méthode de la superclasse.
Par exemple : on peut outrepasser une méthode declarée protected
et la déclarer public
:
public class SuperClass {
protected void doSomeThing() { }
}
public class SubClass extends SuperClass {
public void doSomeThing() { }
}
-
La méthode outrepassante peut lancer (throw) n'import quelle exception non-vérifiée (par le compilateur),
indépendamment si la méthode de la superclasse lance ou non cette exception.
public class SuperClass {
public void doSomeThing() { }
}
public class SubClass extends SuperClass {
public void doSomeThing() throws RuntimeException { }
}
-
La méthode outrepassante ne peut pas lancer des exceptions vérifiées (par le compilateur) qui ne sont pas lancées par la méthode de la superclasse.
public class SuperClass {
public void doSomeThing() { }
}
public class SubClass extends SuperClass {
public void doSomeThing() throws FileNotFoundException { } // compiler error: Exception FileNotFoundException is not compatible with throws clause in SuperClass.doSomeThing()
}
-
La méthode outrepassante peut ne pas lancer les exceptions vérifiées (par le compilateur) qui sont lancées par la méthode de la superclasse.
public class SuperClass {
public void doSomeThing() throws FileNotFoundException { }
}
public class SubClass extends SuperClass {
public void doSomeThing() { }
}
Il faut rappeler que le compilateur considère uniquement le type de la variable pour décider
si c'est la version de la superclasse ou celle de la sous-classe qui sera exécutée.
Donc si le type de la variable est celui de la superclasse, alors il faut mettre l'appel de la méthode à l'intérieur du bloc try-catch
,
sinon le compilateur affichera une erreur :
public class TestClass {
public static void main(String[] args) {
SuperClass superClass1 = new SuperClass();
SuperClass superClass2 = new SubClass();
SubClass subClass1 = new SubClass();
superClass1.doSomeThing(); // compiler error: Unhandled exception type FileNotFoundException
superClass2.doSomeThing(); // compiler error: Unhandled exception type FileNotFoundException
subClass1.doSomeThing(); // OK
}
}
-
La méthode outrepassante peut lancer uniquement des exceptions vérifiées (par le compilateur) qui sont du même type ou un sous-type des exceptions lancées par la méthode de la superclasse.
public class SuperClass {
public void doSomeThing() throws IOException { }
}
public class SubClass extends SuperClass {
public void doSomeThing() throws FileNotFoundException, ZipException { }
}
Au cas contraire le compilateur affichera un message d'erreur :
public class SuperClass {
public void doSomeThing() throws FileNotFoundException { }
}
public class SubClass extends SuperClass {
public void doSomeThing() throws IOException { } // compiler error: Exception IOException is not compatible with throws clause in SuperClass.doSomeThing()
}