11
votes

Java Generics - Déducing de type

Considérez les éléments suivants:

 public class GenericTest {
    static void print(int x) {
        System.out.println("Int: " + x);
    }
    static void print(String x) {
        System.out.println("String: " + x);
    }

    static void print(Object x) {
        System.out.println("Object: " + x);
    }

    static <T> void printWithClass(T t) {
        print(t);
    }
    public static void main(String argsp[]) {
        printWithClass("abc");
    }
}


1 commentaires

Voir cette question sur obtenir le type de T - Obtenez un type de classe générique à l'exécution < / a>


8 Réponses :


4
votes

Java prend en charge la méthode de remplacement (reliure de type dynamique), mais pas ce que vous essayez d'atteindre (la surcharge est un polymorphisme statique et non dynamique).

Pour réaliser ce que vous voulez réaliser en Java, vous avez besoin d'une double envoi. . P>

Modèle de visiteur devrait être votre ami ici. P>

Je vous ai écrit un échantillon de code. P>

public class Test {

    public static void main(String argsp[]) {
        PrintTypeImpl typeImpl = new PrintTypeImpl(new StringType(), new IntType(), new ObjectType());
        typeImpl.accept(new PrintVisitor());
    }

    static final class PrintVisitor implements TypeVisitor {
        public void visit(IntType x) {
            System.out.println("Int: ");
        }

        public void visit(StringType x) {
            System.out.println("String: ");
        }

        public void visit(ObjectType x) {
            System.out.println("Object: ");
        }
    }

    interface TypeVisitor {
        void visit(IntType i);

        void visit(StringType str);

        void visit(ObjectType obj);
    }

    interface PrintType {
        void accept(TypeVisitor visitor);
    }

    static class StringType implements PrintType {
        @Override
        public void accept(TypeVisitor visitor) {
            visitor.visit(this);
        }
    }

    static class ObjectType implements PrintType {
        @Override
        public void accept(TypeVisitor visitor) {
            visitor.visit(this);
        }
    }

    static class IntType implements PrintType {
        @Override
        public void accept(TypeVisitor visitor) {
            visitor.visit(this);
        }
    }

    static final class PrintTypeImpl implements PrintType {

        PrintType[] type;

        private PrintTypeImpl(PrintType... types) {
            type = types;
        }

        @Override
        public void accept(TypeVisitor visitor) {
            for (int i = 0; i < type.length; i++) {
                type[i].accept(visitor);
            }
        }
    }

}


0 commentaires


0
votes

Parce que cela peut savoir que seul le temps d'exécution, mais en réalité, puisque Java est une langue compilée et non un scripté, il est décidé de temps de compilation.

Les génériques Java permettent "un type ou une méthode de fonctionnement sur des objets de différents types tout en fournissant la compilation-time forte> de sécurité de type. " p>

Vous pouvez bien sûr essayer quelque chose comme: p>

static <T extends String> void printWithClass(T t) {
    print(t);
}


0 commentaires

10
votes

Ceci est à cause de Erasure de type Java : votre < pré> xxx

est en fait un sucre syntaxique sur xxx

être juste, que "sucre syntaxique" permet au compilateur de faire très belle et Vérification importante, mais à l'exécution, il n'y a qu'une seule copie de la méthode printwithclass , et il utilise java.lang.Object comme type de votre variable t .

Si vous avez des génériques expérimentées dans d'autres langues (C #, des modèles C ++, une tentative d'effondrement de type C ++, une effusion de type dépend de ce que vous savez, mais c'est ainsi que cela fonctionne sous la couverture. < / p>


2 commentaires

Il ne s'agit pas d'effacement de type, il s'agit des limites génériques disponibles à la compilation . Si nous utilisons , la sortie est chaîne: abc .


@Daniel Absolument - parce que la méthode deviendrait Void statique Imprimable (String T) ALORS. Mais il resterait une méthode unique, avec un seul type, lié au moment de la compilation pour appeler une surcharge unique de la méthode Static Imprimer .



0
votes
static void printWithClass(Object t) {
    print(t);
}

0 commentaires

0
votes

Les génériques sont interprétés par le compilateur et appliquent une vérification de type supplémentaire pour éviter tout problème de coulée d'exécution. Les informations de type générique sont perdu au moment de l'exécution . Donc, au moment de l'exécution, quelle imprimable reçoit est simplement objet et non à la chaîne et donc votre résultat.


0 commentaires

4
votes

Il ne s'agit pas d'effacement de type, c'est un problème de compilation et la même chose se produirait si les génériques de la méthode stockée JVM sont enregistrées au moment de l'exécution. Il ne s'agit pas non plus de Type Inference - le compilateur infers comme vous l'attendez.

Le problème est que lorsque le compilateur génère du code pour PrintWithClass , il nécessite une signature de méthode spécifique à associer à l'appel impression . Java n'a pas d'envoi multiple. Il ne peut donc pas mettre une signature vague dans la table de la méthode et décider quoi d'invoquer au moment de l'exécution. la seule limite supérieure sur t est objet , donc la seule méthode qui correspond est impression (objet) . < / p>


0 commentaires

0
votes

Exemple supplémentaire pour clarifier:

Number: 1234


0 commentaires