Importations Java statiques

Juste par expérience, j'ai découvert que les méthodes non statiques Java remplacent toutes les mêmes méthodes nommées dans la portée même dans un contexte statique. Même sans permettre la surcharge de paramètre. Comme

import java.util.Arrays;    
import static java.util.Arrays.toString;

public class A {
    public static void bar(Object... args) {
        Arrays.toString(args);
        toString(args);     //toString() in java.lang.Object cannot be applied to (java.lang.Object[])
    }
}

Je ne trouve rien à ce sujet dans spec. Est-ce un bug? Si ce n'est pas le cas, y a-t-il des raisons d'implémenter un langage comme ça?

UPD: Java 6 ne pas compiler cet exemple. La question est pourquoi?

26
demandé sur Lion 2012-01-23 17:11:59

4 réponses

L'explication est simple bien que cela ne change pas le fait que le comportement est très peu intuitif:

Lors de la résolution de la méthode à appeler, la première chose que le compilateur fait est de trouver la plus petite portée englobante qui a une méthode du bon nom. Seulement alors viennent d'autres choses comme la résolution de surcharge et co dans le jeu.

Maintenant, ce qui se passe ici est que la plus petite portée englobante qui contient une méthode toString() est la classe A qui l'hérite de Object. Donc nous arrêter là et ne cherchez pas plus loin. Malheureusement, le compilateur essaie de trouver le meilleur ajustement des méthodes dans la portée donnée et remarque qu'il ne peut appeler aucune de celles-ci et donne une erreur.

Ce qui signifie jamais importer statiquement des méthodes avec un nom identique à une méthode dans Object, car les méthodes qui sont naturellement dans la portée ont la priorité sur les importations statiques (le JLS décrit l'observation de la méthode en détail, mais pour ce problème, je pense qu'il est beaucoup plus simple de n'oubliez pas que).

Edit: @alf a gentiment soumis la partie droite du JLS qui décrit l'invocation de la méthode pour ceux qui veulent l'image entière. C'est plutôt complexe, mais le problème n'est pas simple non plus, donc c'est à prévoir.

22
répondu Voo 2017-05-23 12:24:00

Ce n'est pas un override. Si cela fonctionnait, this.toString() accéderait toujours à la méthode de A au lieu de Arrays.toString comme ce serait le cas si la substitution avait eu lieu.

La spécification de langage explique que les importations statiques n'affectent que la résolution des méthodes et des types static:

Une déclaration d'importation statique unique d dans une unité de compilation c Du paquet p qui importe un champ nommé n ombrage la déclaration de tout champ statique nommé n importé par a statique-import-sur-la demande de déclaration en c, tout au long de c.

Une déclaration d'importation statique unique d dans une unité de compilation c Du paquet p qui importe une méthode nommée N avec la signature s met en ombre la déclaration de toute méthode statique nommée n avec la signature s importée par une déclaration static-import-on-demand en c, tout au long de c.

Une seule déclaration d'importation statique D dans une unité de compilation c Du paquet p qui importe un type nommé n ombrage les déclarations de:

  • tout type statique nommé n importé par une déclaration static-import-on-demand dans c.
  • tout type de niveau supérieur (§7.6) nommé n déclaré dans une autre unité de compilation (§7.3) de p.
  • tout type nommé n importé par une déclaration de type-import-on-demand (§7.5.2) en C. tout au long de c.

Les importations statiques ne masquent pas les méthodes non statiques ou les types internes.

Donc, le toString n'ombre pas le méthode non statique. Comme le nom {[4] } peut faire référence à une méthode non statique de A, Il ne peut pas faire référence à la méthode static de Arrays et donc toString se lie à la seule méthode nommée toString disponible dans la portée, qui est String toString(). Cette méthode ne peut pas prendre d'arguments, donc vous obtenez une erreur de compilation.

La Section 15.12.1 explique la résolution des méthodes et aurait dû être complètement réécrite pour permettre l'ombrage des noms de méthodes indisponibles dans les méthodes static mais pas à l'intérieur des méthodes member.

Je suppose que les concepteurs de langage voulaient garder les règles de résolution de méthode simples, ce qui signifie que le même nom signifie la même chose qu'il apparaisse dans une méthode static ou non, et la seule chose qui change est qui sont disponibles.

4
répondu Mike Samuel 2012-01-23 13:48:03

Si vous essayez de suivre un code similaire, vous n'obtiendrez aucune erreur de compilation

import static java.util.Arrays.sort;
public class StaticImport {
    public void bar(int... args) {
        sort(args); // will call Array.sort
    }
}

La raison pour laquelle cela compile et le vôtre n'est pas que toString() (ou toute autre méthode définie dans class Object) est toujours étendue à Object class parce que Object est le parent de votre classe. Par conséquent, lorsque le compilateur trouve la signature correspondante de ces méthodes à partir de la classe D'objet, il donne une erreur au compilateur. Dans mon exemple, puisque la classe D'objet n'a pas de méthode sort(int[]) par conséquent compilateur correspond à juste titre avec le importation statique .

1
répondu anubhava 2012-01-23 13:43:35

Je ne pense pas que ce soit un bug ou quelque chose de différent de l'importation normale. Par exemple, en cas d'importation normale, si vous avez une classe privée avec le même nom que celle importée, celle importée ne sera pas reflétée.

0
répondu yadab 2012-01-23 13:34:55