2009-11-16 6 views
94

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

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 je l'extrait de code ci-dessous, il compile bien

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

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

Mais si j'inclus modificateur final méthode statique dans la classe A, échoue compilation ts() en B ne peut pas passer outre ts() dans un; méthode substituée est statique final.

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

+0

cela semble bizarre, +1 pour la question, mais jusqu'à présent, aucune des réponses n'est satisfaisante. –

+1

Ce n'est pas écrasé. Il est toujours là à A.ts(). –

Répondre

131

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

Le mot-clé final désactive la méthode pour qu'elle ne soit pas masquée. Donc, ils ne peuvent pas être cachés et une tentative de le faire se traduira par une erreur de compilation.

Espérons que cela aide.

+25

Pour finir peut-être votre réponse, ce qui est juste je crois, le problème ici est fondamentalement un mauvais message d'erreur du compilateur: il devrait indiquer que B ne peut * masquer * ts() dans A. Déclarer une méthode statique final déclare qu'il ne peut pas être caché. –

+2

@Sean Owen: Je le pense aussi. Le terme 'hide' est même utilisé dans Java Specification 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? – immibis

11

méthodes statiques ne peuvent pas être écrasées

Ce n'est pas tout à fait vrai. L'exemple de code signifie en fait que la méthode ts de B masque la méthode ts dans A. Donc, ce n'est pas exactement écrasant. Plus sur Javaranch il y a une bonne explication.

+3

Il est vrai que ce n'est 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. –

+0

Malheureusement, votre lien ne fonctionne plus. Est-il possible de réparer ça? –

0

La méthode ts() dans B ne surcharge 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, donc elle peut déclarer sa propre méthode appelée ts().

Cependant, si la méthode est définitive, le compilateur ramasser qu'il ya une méthode ts() dans A qui ne devrait pas être surchargée dans B.

+0

Je ne pense pas que cela explique pourquoi «final» signifie soudainement que ces méthodes ne peuvent pas coexister. Comme vous le dites, sans «finale», il n'y a pas de problème. Vous dites que ce n'est pas prioritaire, mais dites que le problème est que B ne peut pas remplacer la méthode de A. –

+0

Bien sûr, j'affirme 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, d'accord. – amischiefr

9

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

A.ts() et B.ts() seront toujours des méthodes séparées.

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 hidden lorsqu'elles sont appelées à partir d'une instance de la sous-classe. Toutefois, vous ne pouvez pas remplacer/masquer final methods.

On pourrait penser le message d'erreur utiliserait le mot caché au lieu de ... substituée

1

Je pense que l'erreur de compilation était tout à fait induire en erreur ici. Il n'aurait pas dû dire que "la méthode surchargée est statique finale.", Mais elle aurait dû dire "la méthode surchargée est finale". Le modificateur statique n'est pas pertinent ici.

+0

Donc, vous considérez la méthode statique dans B remplaçant celle dans A? –

4

Vous pourriez vous retrouver en mesure de penser à faire une finale de méthode statique, considérant ce qui suit:

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 façon « correcte » d'appeler ces méthodes serait

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

qui aurait pour conséquence AB mais vous pouvez aussi appeler les méthodes sur les instances:

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

qui entraînerait également AB.

considèrent maintenant comme suit:

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

qui imprimerait A. Cela pourrait vous surprendre puisque vous avez réellement un objet de la classe B. Mais puisque vous l'appelez à partir d'une référence de type A, il appellera A.ts(). Vous pouvez imprimer B avec 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 en fonction du pointeur qui pointe vers l'objet, vous appellerez méthode de A ou de B.

Maintenant, disons que vous êtes le développeur de la classe A et que vous voulez autoriser le sous-classement. Mais vous voulez vraiment la méthode ts(), à chaque appel, même à partir d'une sous-classe, c'est ce que vous voulez faire et ne pas être caché par une version de sous-classe. Ensuite, vous pouvez le faire final et l'empêcher d'être caché dans la sous-classe. Et vous pouvez être sûr que le code suivant appelle la méthode de votre classe A:

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

Ok, admittetly qui est en quelque sorte construit, mais il pourrait être logique pour certains cas.

Vous ne devez pas appeler des méthodes statiques sur des instances, mais directement sur les classes. Vous n'aurez donc pas ce problème. Aussi IntelliJ IDEA par exemple vous montrera un avertissement, si vous appelez une méthode statique sur une instance et si vous définissez une méthode statique finale.

Questions connexes