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.

enter image description here

j'utilise JDK 6.

20
demandé sur Tiny 2012-10-14 10:39:10

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: -

  1. Primitive élargissement utilise le smallest argument d'une méthode possible
  2. Wrapper type ne peut être élargie à un autre type Wrapper
  3. vous pouvez Box de int À entier et élargir à Objet mais pas à Long
  4. L'élargissement bat la boxe, la boxe Bat Var-args.
  5. vous pouvez Boxer puis élargir (un int peut devenir Object via Integer )
  6. on ne peut pas s'Élargir et puis Box (Un int ne peut devenir Long )
  7. 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 puis Boxed pour entrer dans un Long , 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

9
répondu Rohit Jain 2013-07-29 20:54:46

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).

2
répondu Bruno Reis 2012-10-14 06:49:05

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.

2
répondu Bhesh Gurung 2017-05-23 11:46:21

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.

2
répondu Yogendra Singh 2016-07-23 23:37:57