Pourquoi si la méthode statique n’implique pas de polymorphism (liaison tardive), une erreur est signalée: cette méthode statique ne peut pas être remplacée

veuillez considérer le code suivant:

class A{ public static void m(Number n){ System.out.println("Number A"); }; } class B extends A{ public static int m(Number n){ System.out.println("Number B"); return 1; }; } 

sortie:

java: m (java.lang.Number) dans inheritanceTest.B ne peut pas remplacer m (java.lang.Number) dans inheritanceTest.Un type de retour int n’est pas compatible avec void

Je sais que les méthodes statiques n’impliquent pas de polymorphism, c’est pourquoi je déduis que le dépassement est impossible pour mon code. Ce message du compilateur est étrange pour moi.

Si je comprends bien, le fait de faire partie du polymorphism est primordial. Je me prépare pour scjp et j’ai peur de me tromper en question familière.

S’il vous plaît clarifier cette question.

comportement attendu pour moi – message concernant une erreur de surcharge

P.S1.

J’ai lu la question la plus populaire sur la statique remplacée et je n’ai pas trouvé de réponse (

P.S2. Selon la réponse de Pshemo:

ce code:

 class Foo{ public static void m(Number n){ System.out.println("Number A"); }; public static int m(Number n){ System.out.println("Number B"); return 1; }; } 

les sorties:

 error: method m(Number) is already defined in class Foo public static int m(Number n){ ^ 1 error 

Pour moi, ces situations sont les mêmes. Mais l’erreur du compilateur est différente – étrange.

JLS §8.4.8.3 (Java 8) dit:

Si une déclaration de méthode d 1 avec le type de retour R 1 annule ou masque la déclaration d’une autre méthode d 2 avec le type de retour R 2 , alors d 1 doit être substituable en tant que type de retour (§8.4.5) pour d 2 , ou une compilation -time erreur se produit.

Cette même règle s’applique aux méthodes d’instance et aux méthodes statiques, car elle dit “remplace ou masque”. Fondamentalement, si vous avez une méthode avec le même nom et les mêmes parameters, elle remplace si c’est une méthode d’instance, mais cache (la méthode héritée) s’il s’agit d’une méthode de classe (statique). Et dans les deux cas, le type de retour doit être identique ou obéir aux règles de covariance.

Puisqu’il s’agit de la même règle, il est probable que le code du compilateur ne vérifie cette règle qu’à un seul endroit. Si la règle est violée, vous obtenez l’erreur que vous constatez, ce qui, j’en suis sûr, est beaucoup plus fréquent. Le compilateur devrait vraiment vérifier s’il doit dire “remplace” ou “cache”, mais il semble qu’ils aient glissé. Obtenir le message d’erreur exact n’est généralement pas la plus haute priorité des rédacteurs du compilateur – ce n’est pas comparé à s’assurer que le code qui est censé être compilé le fait et fonctionne correctement, et que le code qui n’est pas censé être compilé ne le fait pas. Je pense donc que c’est une lacune, mais très mineure.

Même si les méthodes statiques ne peuvent pas être remplacées, elles sont toujours héritées de sorte que ce que vous essayez de faire aboutirait à une situation similaire à

 class Foo{ public static void m(Number n){ System.out.println("Number A"); }; public static int m(Number n){ System.out.println("Number B"); return 1; }; } 

ce qui est faux parce que vous ne pouvez pas avoir deux méthodes avec la même signature mais avec des types de retour différents. La raison pour laquelle cela a été interdit est assez simple: le compilateur ne serait pas en mesure de décider quelle méthode de méthode Foo method() Bar method() vous voudriez invoquer par exemple dans des situations telles que

 System.out.println(method);//should result be Foo or Bar? 

Pour éviter ce genre de situation, le compilateur interdit de remplacer / masquer les méthodes avec la même signature en modifiant ses types de retour. La seule exception est lorsque vous remplacez le type de retour par un type plus détaillé, comme

 class X{ List m(){...} } class Y extends X{ LinkedList m(){...} } 

Donc, il semble que cette override n’est pas le meilleur mot. Le mot correct doit être masqué car les méthodes statiques peuvent être masquées, non remplacées, mais puisque la même règle permet de vérifier les méthodes substituées / cachées, son message d’erreur est plus général.

Je pense que l’utilisation d’erreur de «surpassement» par le compilateur est trompeuse ici, elle n’est pas applicable.

La langue spécifie :

Si une déclaration de méthode d1 avec le type de retour R1 annule ou masque la déclaration d’une autre méthode d2 avec le type de retour R2, d1 doit être substituable en retour par type de type d2 ou une erreur lors de la compilation se produit.

Ici, votre méthode B cache la déclaration de Am:

Si une classe déclare une méthode statique m, la déclaration m cache toute méthode m ‘, où la signature de m est une sous-signature (§8.4.2) de la signature de m’, dans les superclasses et les superinterfaces du classe qui serait autrement accessible au code de la classe.

Si votre classe B n’avait pas de méthode m, vous pourriez appeler Bm et appeler le m défini sur A.

Avoir Bm cache la version de A de m. Dans la mesure où vous pouvez appeler une méthode statique définie sur une superclasse mais référencer la sous-classe, cela définit certaines attentes relatives à la méthode qui sont violées par le type de retour différent.

C’est caché et non prioritaire parce que si vous avez un Bm défini, vous pouvez toujours appeler Am et obtenir la version de la méthode de la superclasse. Avec la substitution, c’est le type d’exécution qui décide comment appeler et comment il s’appelle importe peu.