Comportement de la méthode statique finale

123

J'ai joué avec des modificateurs avec une méthode statique et je suis tombé sur un comportement étrange.

Comme nous le savons, les méthodes statiques ne peuvent pas être remplacées, car elles sont associées à une classe plutôt qu'à une instance.

Donc, si j'ai l'extrait ci-dessous, il se compile bien

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}

Mais si j'inclus le modificateur final à la méthode statique dans la classe A, alors la compilation échoue ts () dans B ne peut pas remplacer ts () dans A; la méthode remplacée est statique final .

Pourquoi cela se produit-il lorsque la méthode statique ne peut pas du tout être remplacée?

Harish
la source
2
cela semble bizarre, +1 pour la question, mais jusqu'à présent, aucune des réponses n'est satisfaisante.
Rakesh Juyal
1
Ce n'est pas annulé. Il est toujours là chez A.ts ().
Alex Feinman

Réponses:

166

Les méthodes statiques ne peuvent pas être remplacées mais elles peuvent être masquées. La ts()méthode de B ne remplace pas (non sujette au polymorphisme) la ts()de A mais elle le cachera. Si vous appelez ts()en B (PAS A.ts()ou B.ts()... juste ts()), celui de B sera appelé et non A. Comme il n'est pas soumis au polymorphisme, l'appel ts()en A ne sera jamais redirigé vers celui de B.

Le mot final- clé désactivera le masquage de la méthode. Ils ne peuvent donc pas être masqués et une tentative de le faire entraînera une erreur du compilateur.

J'espère que cela t'aides.

NawaMan
la source
30
Pour peut-être terminer votre réponse, ce qui est juste je crois, le problème ici est essentiellement un mauvais message d'erreur du compilateur: il devrait indiquer que B ne peut pas cacher ts () dans A. Déclarer une méthode statique final, c'est déclarer qu'elle ne peut pas être cachée.
Sean Owen
2
@Sean Owen: Je le pense aussi. Le terme «masquer» est même utilisé dans la spécification Java, alors pourquoi ne pas l'utiliser dans le message du compilateur.
NawaMan
2
Pourquoi est-ce même une fonctionnalité? Dans quel contexte serait-il utile?
user253751
public class Test {final static public void main (String ... srik) {System.out.println ("In main method"); ts (); } public static void ts () {Child c = new Child (); c.ts (); System.out.println ("Test ts"); }} classe publique Child s'étend Test {public static void ts () {System.out.println ("Child ts"); }} Salut Pouvez-vous m'expliquer ce qui se passe dans ce scénario
srikanth r
@SeanOwen Je ne pense pas que ce soit correct non plus, le compilateur devrait dire que puisque A#tsc'est hérité et qu'une telle méthode existe déjà B, avoir simplement deux méthodes avec la même signature et un modificateur différent ( final) ne fonctionnerait pas comme des surcharges .. . J'aimerais pouvoir penser à un message simple pour cela, cependant
Eugene
13

les méthodes statiques ne peuvent pas être remplacées

Ce n'est pas tout à fait vrai. L'exemple de code signifie vraiment que la méthode ts dans B masque la méthode ts dans A. Donc, ce n'est pas exactement la substitution. Sur Javaranch, il y a une belle explication.

Vincent Ramdhanie
la source
4
C'est vrai mais pas précis. Les méthodes statiques ne peuvent pas être remplacées mais peuvent être masquées si vous les appelez sur une référence d'instance plutôt que sur le nom de la classe.
John Mercier
1
Malheureusement, votre lien ne fonctionne plus. Est-il possible de réparer ça?
Mathias Bader
Le lien javaranch ne fonctionne pas, mais googler les mots clés a révélé ce lien sur code ranch
Sundeep
J'ai édité l'article en remplaçant le lien mort par le lien publié par Sundeep.
MC Emperor
10

Les méthodes statiques appartiennent à la classe, pas à l'instance.

A.ts()et B.ts()seront toujours des méthodes distinctes.

Le vrai problème est que Java vous permet d'appeler des méthodes statiques sur un objet d'instance. Les méthodes statiques avec la même signature de la classe parent sont masquées lorsqu'elles sont appelées depuis une instance de la sous-classe. Cependant, vous ne pouvez pas remplacer / masquer les méthodes finales .

Vous penseriez que le message d'erreur utiliserait le mot caché au lieu de remplacé ...

Powerlord
la source
6

Vous pourriez vous trouver en position de penser à rendre une méthode statique définitive, compte tenu des éléments suivants:

Avoir les classes suivantes:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

Maintenant, la manière `` correcte '' d'appeler ces méthodes serait

A.ts();
B.ts();

ce qui entraînerait ABmais vous pourriez également appeler les méthodes sur les instances:

A a = new A();
a.ts();
B b = new B();
b.ts();

ce qui en résulterait ABégalement.

Considérez maintenant ce qui suit:

A a = new B();
a.ts();

cela imprimerait A. Cela pourrait vous surprendre puisque vous avez en fait un objet de classe B. Mais puisque vous l'appelez à partir d'une référence de type A, il appellera A.ts(). Vous pouvez imprimer Bavec le code suivant:

A a = new B();
((B)a).ts();

Dans les deux cas, l'objet que vous avez est en fait de la classe B. Mais selon le pointeur qui pointe vers l'objet, vous appellerez la méthode from Aou from B.

Disons maintenant que vous êtes le développeur de la classe Aet que vous souhaitez autoriser le sous-classement. Mais vous voulez vraiment que la méthode ts(), chaque fois qu'elle est appelée, même à partir d'une sous-classe, fasse ce que vous voulez qu'elle fasse et ne soit pas masquée par une version de sous-classe. Ensuite, vous pouvez le créer finalet l'empêcher d'être caché dans la sous-classe. Et vous pouvez être sûr que le code suivant appellera la méthode à partir de votre classe A:

B b = new B();
b.ts();

Ok, admettre que c'est en quelque sorte construit, mais cela peut avoir du sens dans certains cas.

Vous ne devez pas appeler de méthodes statiques sur les instances mais directement sur les classes - alors vous n'aurez pas ce problème. IntelliJ IDEA, par exemple, vous montrera également un avertissement, si vous appelez une méthode statique sur une instance et aussi si vous rendez une méthode statique définitive.

Mathias Bader
la source
0

La méthode ts () dans B ne remplace pas la méthode ts () dans A, c'est simplement une autre méthode. La classe B ne voit pas la méthode ts () dans A car elle est statique, elle peut donc déclarer sa propre méthode appelée ts ().

Cependant, si la méthode est finale, le compilateur détectera qu'il existe une méthode ts () dans A qui ne devrait pas être remplacée dans B.

amischiefr
la source
Je ne pense pas que cela explique pourquoi «final» signifie soudainement que ces méthodes ne peuvent pas coexister. Comme vous le dites, sans «final», il n'y a pas de problème. Vous dites que ce n'est pas une priorité, mais vous dites ensuite que le problème est que B ne peut pas remplacer la méthode de A.
Sean Owen
Bien sûr que oui, je déclare que B ne voit pas la méthode ts () dans A (elle est «cachée»), mais le modificateur final ne «cache» pas les méthodes des classes qui en étendent une autre. Mais hein, ok.
amischiefr
0

Je pense que l'erreur de compilation était assez trompeuse ici. Il n'aurait pas dû dire «la méthode surchargée est finale statique», mais il aurait dû plutôt dire «la méthode surchargée est définitive». Le modificateur statique n'est pas pertinent ici.

BalusC
la source
1
Vous considérez donc que la méthode statique de B remplace celle de A?
Koray Tugay
@KorayTugay Je me demande simplement si le compilateur examine d'abord la méthode potentiellement remplaçable (ignore la statique pendant un moment), voit la finale en échec. Juste une supposition sauvage
Eugene
Balus Je pense que c'est la seule réponse de faible qualité que vous ayez dans StackOverflow. Compte tenu de toutes vos réponses exceptionnelles, celle-ci ne leur appartient pas. @BalusC
Koray Tugay
@KorayTugay: à ce moment-là, je n'avais pas assez de réputation pour commenter :) Si vous envoyez un ping, je supprimerai la réponse, pas de problème.
BalusC
0

Une méthode statique ne peut pas être remplacée en Java, contrairement aux méthodes non statiques. Mais ils sont hérités comme des membres de données statiques et non statiques. C'est pourquoi une méthode non statique avec le même nom ne peut pas être créée dans la classe parente

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

Le finalmot clé garantit que le corps de la méthode spécifique sera exécuté à chaque fois qu'un appel à la méthode. Maintenant, si une méthode statique est créée dans la classe enfant avec le même nom et qu'un appel à la méthode est effectué, la méthode de la sous-classe est exécutée, ce qui ne devrait pas être le cas si final est préfixé avant le nom de la méthode statique dans la classe parent . Par conséquent, le mot-clé final limite la création d'une méthode avec le même nom dans la classe enfant.

Pratik Gupta
la source