Varargs dans la surcharge de méthode en Java
le code suivant ne se compile pas.
package varargspkg;
public class Main {
public static void test(int... i) {
for (int t = 0; t < i.length; t++) {
System.out.println(i[t]);
}
System.out.println("int");
}
public static void test(float... f) {
for (int t = 0; t < f.length; t++) {
System.out.println(f[t]);
}
System.out.println("float");
}
public static void main(String[] args) {
test(1, 2); //Compilation error here quoted as follows.
}
}
une erreur de compilation est émise.
référence de test est ambiguë, à la fois la méthode de test(int...) dans varargspkg.Essai principal et essai de méthode(float...) in varargspkg.Main match
cela semble évident parce que les valeurs des paramètres dans l'appel de méthode test(1, 2);
peuvent être promues à int
aussi bien que float
si l'un des paramètres ou les deux sont suffixés par F
ou f
, il se compile.
si nous représentons les paramètres de réception dans la méthode signature avec les types d'enveloppe respectifs comme suit
public static void test(Integer... i) {
System.out.println("Integer" + Arrays.asList(i));
}
public static void test(Float... f) {
System.out.println("Float" + Arrays.asList(f));
}
puis l'appel à la méthode test(1, 2);
n'émet pas d'erreur de compilation. La méthode à invoquer dans ce cas est celle qui accepte une Integer
paramètre varargs (le premier dans l'extrait précédent).
Pourquoi dans ce cas l'erreur comme dans le premier cas non déclarés? Il semble que l'auto-boxe et la promotion de type automatique soient appliquées ici. L'auto-boxe est-elle appliquée en premier pour que l'erreur soit résolue?
L'Oracle docs dit,
en général, vous ne devez pas surcharger une méthode varargs, ou il il sera difficile pour programmeurs pour déterminer quelle surcharge obtient appelé.
La dernière phrase de cette lien . Mais c'est pour mieux comprendre varargs.
aussi pour ajouter ci-dessous le code compile très bien.
public class OverLoading {
public static void main(String[] args) {
load(1);
}
public static void load(int i) {
System.out.println("int");
}
public static void load(float i) {
System.out.println("float");
}
}
modifier:
ce qui suit est le snap shot que indique l'erreur de compilation. J'ai créé une nouvelle application, donc le nom du paquet est différent.
j'utilise JDK 6.
4 réponses
vous pouvez soit Widen
ou Box
mais vous ne pouvez pas faire les deux, à moins que vous ne soyez boxing and widening
à Object
(un int à Integer(Boxing) et puis Integer à Object(Widening) est légal, puisque chaque classe est une sous-classe de Object
, de sorte qu'il est possible de passer Integer
à Object
paramètre)
de même, int
à Number
est également légal (int - > entier - > Nombre)
Puisque le nombre est la super classe de Integer
il est possible.
voyons cela dans votre exemple: -
public static void test(Integer...i)
public static void test(Float...f)
il y a des règles qui sont suivies lors de la sélection de la méthode surchargée à sélectionner, lorsque la boxe, L'élargissement et Var-args sont combinés: -
- Primitive élargissement utilise le
smallest
argument d'une méthode possible - Wrapper type ne peut être élargie à un autre type Wrapper
- vous pouvez Box de int À entier et élargir à Objet mais pas à Long
- L'élargissement bat la boxe, la boxe Bat Var-args.
- vous pouvez Boxer puis élargir (un
int
peut devenirObject
viaInteger
) - on ne peut pas s'Élargir et puis Box (Un
int
ne peut devenirLong
) - vous ne pouvez pas combiner var-args, avec l'élargissement ou la boxe
, sur la base des données ci-dessus les règles: -
lorsque vous passez deux entiers aux fonctions ci-dessus,
- selon la règle 3, il devra être d'abord
Widened
et puisBoxed
pour entrer dans unLong
, ce qui est illégal selon la règle 5 (vous ne pouvez pas élargir et puis Boxer). - ainsi, il est emballé pour stocker dans
Integer
var-args.
mais dans le premier cas, où vous avez des méthodes avec var-args
de types primitifs: -
public static void test(int...i)
public static void test(float...f)
puis test(1, 2)
peuvent invoquer les deux méthodes (car aucune d'elles n'est plus appropriée pour rule 1
à appliquer): -
- dans le premier cas il sera
var-args
- dans le deuxième cas, il sera L'élargissement et puis Var-args (qui est autorisé)
maintenant, quand vous avez des méthodes avec exactement un int et un flost: -
public static void test(int i)
public static void test(float f)
puis en invoquant test(1)
, la règle 1 est suivie, et le plus petit élargissement possible (c'est-à-dire le int
où aucun élargissement n'est nécessaire) est choisi. Donc 1ère méthode sera invoquée.
pour plus d'informations, vous pouvez vous référer à JLS - Method Invocation Conversion
en Java, 1
est la façon dont vous représentez un int
. Il peut être soit auto-boxe à une instance de Integer
ou promu à float
, et cela explique pourquoi le compilateur ne peut pas décider de la méthode qu'il devrait appeler. Mais il ne sera jamais auto-boxé à Long
ou Float
(ou tout autre type).
, d'autre part, si vous écrivez 1F
, c'est la représentation d'une float
, qui peut être auto-coffret à un Float
(et, dans le même esprit, ne sera jamais auto-boxé à un Integer
ou quoi que ce soit d'autre).
Pourquoi dans ce cas l'erreur comme dans le premier cas non déclarés? Il semble que l'auto-boxe et la promotion de type automatique soient appliquées ici. L'auto-boxe est-elle appliquée en premier l'erreur est résolue?
Juste un avis en cas de varargs la JVM a effectivement de créer un tableau d'arguments. Dans le cas D'entier et de flottant, il est évident quel type de tableau il devrait créer. Donc, probablement qu'elle pourrait en être la cause d'aucune ambiguïté erreur.
mais quand même, c'est un peu confus, pourquoi il ne peut pas créer un tableau D'entiers, quand par défaut 1, 3 sont des ints.
on dirait que cela a été discuté ici dans le passé bug avec varargs et surcharge? et est en fait bug , selon la discussion.
en Java 6, le problème réside au moment de instantiation
de vos génériques avant de trouver quelle méthode est disponible à appeler.
When you write 1,2
-> it can be be both int[] or float[] and hence the issue being complained.
When you write 1,2F
-> it can be be only float[] and hence the NO issue being complained.
idem avec deux autres options, à savoir
When you write 1F,2
-> it can be be only float[] and hence the NO issue being complained.
When you write 1F,2F
-> it can be be only float[] and hence the NO issue being complained.
par contre, lorsque vous utilisez int
ou float
, il n'y a pas d'instanciation de type variable. Quand vous utilisez 1
, il essaie de trouver la méthode avec int
comme argument d'abord, si non, il promeut le type et identifie la méthode avec flotteur. Si les deux méthodes sont disponibles, une avec le int
sera utilisée en premier.
Ambiguïté problème ne viendra pas dans Java 7 car il a une meilleure gestion des données de vérification de type et de promotion.