Passer des arguments d'octet à une méthode surchargée

12

J'ai pris cet extrait de code d'un quiz, en utilisant IDE je l'ai exécuté et j'obtiens un résultat long, long mais la bonne réponse est Byte, Byte , pourquoi j'ai obtenu un résultat différent? La question est liée à JDK 11

public class Client {
    static void doCalc(byte... a) {
        System.out.print("byte...");
    }

    static void doCalc(long a, long b) {
        System.out.print("long, long");
    }

    static void doCalc(Byte s1, Byte s2) {
        System.out.print("Byte, Byte");
    }

    public static void main(String[] args) {
        byte b = 5;
        doCalc(b, b);
    }
}

ÉDITÉ:

Le code a été pris ici: Présentation de la certification Oracle et exemples de questions (page: 13, question: 5)

kbo
la source
1
Êtes-vous sûr que ce n'est pas Byte b = 5;avec un B majuscule?
Joop Eggen
4
Je reçois long, longaussi Java8 pour info ... Je ne sais pas pourquoi pour être honnête, j'attends aussi une réponse :)
sp00m

Réponses:

6

Alors, si vous passez par le langage Java spécification pour déterminer la signature de la méthode au moment de la compilation , il sera clair:

  1. La première phase (§15.12.2.2) effectue une résolution de surcharge sans autoriser la conversion de boxing ou unboxing ou l'utilisation de l'invocation de la méthode d'arité variable. Si aucune méthode applicable n'est trouvée pendant cette phase, le traitement se poursuit jusqu'à la deuxième phase.

  2. La deuxième phase (§15.12.2.3) effectue une résolution de surcharge tout en autorisant la mise en boîte et la décompression, mais empêche toujours l'utilisation de l'invocation de la méthode d'arité variable. Si aucune méthode applicable n'est trouvée pendant cette phase, le traitement se poursuit jusqu'à la troisième phase.

  3. La troisième phase (§15.12.2.4) permet de combiner la surcharge avec des méthodes d'arité variable, la boxe et le déballage.

Ainsi, à partir des étapes ci-dessus, il est clair que dans votre cas, dans la première phase, le compilateur Java trouvera une méthode de correspondance qui le fait doCalc(long a,long b). Votre méthode a doCalc(Byte s1, Byte s2)besoin d'un autoboxing pendant l'appel, donc elle aura moins de préférence.

Amit Bera
la source
1
Concernant pourquoi longaccepte byte, semble suivre une conversion primitive élargie : docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 . Donc , fondamentalement, +widening -boxing -varargspuis +widening +boxing -varargsensuite +widening +boxing +varargs.
sp00m
@kbo Pourquoi pensez-vous que la bonne réponse est Byte, Byte?
Amit Bera
3
@kbo Je suppose que la bonne réponse est incorrecte :) Cela pourrait valoir la peine de pointer les auteurs vers cette question si vous le pouvez.
sp00m
3
@ sp00m J'ai trouvé cette question dans les échantillons d'Oracle, veuillez jeter un œil à la partie modifiée
kbo
@kbo Wow ... Aucune idée de comment procéder alors!
sp00m
2

Veuillez lire le chapitre JLS sur les conversions .

Ce qui se passe dans votre cas, c'est que pendant l'exécution, la machine virtuelle Java choisit d'effectuer une conversion d'élargissement byte -> long car cette conversion est plus sûre car il est garanti qu'elle ne provoque pas RuntimeException.

La conversion de byteà Byteégalement appelée boxe peut entraîner OutOfMemoryError car la JVM doit allouer de nouveaux objets sur le tas:

Une conversion de boxe peut entraîner une OutOfMemoryError si une nouvelle instance de l'une des classes wrapper (booléen, octet, caractère, court, entier, long, flottant ou double) doit être allouée et qu'un stockage insuffisant est disponible.

Pour cette raison, la byte -> long conversion d'élargissement plus sûre est préférée.

diginoise
la source
2
Juste à noter, la boxe de byteà Bytene provoque jamais OutOfMemoryException, car toutes les valeurs de Byte(-128 - 127) sont mises en cache en interne. Mais il peut ne pas être le même avec d'autres types, donc comme règle générale, l'élargissement de la conversion devient prioritaire.
Pavel Smirnov
1

Pour trouver la surcharge correcte, la commande est:

  1. par nombre de paramètres
  2. boxe / déballage
  3. paramètres variadiques

Donc

  • Si bBytele résultat serait Byte, Byte.
  • S'il avait été adopté, new byte[] { b, b }le résultat serait byte, byte.
  • Si passé deux octets b, un élargissement de l'octet à l'int à long est possible et le résultat est long, long.
  • Lorsque la surcharge longue, longue est supprimée, il en Byte, Byterésulte.
Joop Eggen
la source