10 votes

getMethods() renvoie une méthode que je n'ai pas définie lors de l'implémentation d'une interface générique

Une interface simple :

interface Foo {
    void myMethod(String arg);
}

class FooImpl implements Foo {
    void myMethod(String arg){}

    public static void main(String[] args) {
    Class cls = FooImpl.class;
    try {
        for (Method method : cls.getMethods()) {
        System.out.print(method.getName() + "\t");
        for(Class paramCls : method.getParameterTypes()){
            System.out.print(paramCls.getName() + ",");
        }
        System.out.println();
        }
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
    }
    }
}

La sortie serait :

myMethod java.lang.String,
...//Other Method

Un seul myMethod est imprimé.

Mais si je change l'interface pour une interface générique :

interface Foo<T> {
    void myMethod(T arg);    
}   

class FooImpl implements Foo<String> {
    void myMethod(String arg){}
}

Alors bizarrement la sortie sera :

myMethod java.lang.Object,
myMethod java.lang.String,
...//Other Method

Pourquoi, après avoir changé l'interface en une interface générique, une méthode de plus avec un paramètre de type objet est-elle nécessaire ?

6voto

Fortega Points 8890

La première méthode est une méthode de pontage créé par le compilateur. Si vous testez vos méthodes pour ' isBridge() ', vous pouvez filtrer les "mauvaises" méthodes (vous pouvez également filtrer certains résultats étranges que vous pouvez obtenir avec les retours de covariance).

Le code suivant n'imprimera pas le myMethod java.lang.Object :

import java.lang.reflect.Method;

public class FooImpl implements Foo<String> {
    public void myMethod(String arg) {
    }

    public static void main(String[] args) throws Exception {
        Class cls = FooImpl.class;
        for (Method method : cls.getMethods()) {
            if (!method.isBridge()) {
                System.out.print(method.getName() + "\t");

                for (Class paramCls : method.getParameterTypes()) {

                    System.out.print(paramCls.getName() + ",");

                }
            }
            System.out.println();
        }
    }
}

interface Foo<T> {
    public void myMethod(T arg);
}

2voto

Narendra Pathai Points 12172
try {
        for (Method method : cls.getMethods()) {
    //these methods are called bridge methods       
            if(!method.isBridge()){
                System.out.print(method.getName() + "\t");
                for(Class paramCls : method.getParameterTypes()){
                    System.out.print(paramCls.getName() + ",");
                }
                System.out.println();
            }
        }
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
    }

UPDATE : Méthodes de pontage

Je cite le blog :

Les méthodes de pont en Java sont des méthodes synthétiques, qui sont nécessaires pour mettre en œuvre certaines fonctionnalités du langage Java. Les plus connues sont type de retour covariant et un cas dans les génériques où l'effacement des arguments de la méthode de base diffère de celui de la méthode réellement invoquée.

CODE DE MISE À JOUR DU blog ci-dessus :

public class SampleTwo {
    public static class A<T> {
        public T getT(T args) {
            return args;
        }
    }

    public static class B extends A<String> {
        public String getT(String args) {
            return args;
        }
    }
}

Lors de la compilation, le code sera le suivant :

public SampleThree$B();
...
public java.lang.String getT(java.lang.String);
Code:
0:   aload_1
1:   areturn

public java.lang.Object getT(java.lang.Object);
Code:
0:   aload_0
1:   aload_1
2:   checkcast       #2; //class java/lang/String
5:   invokevirtual   #3; //Method getT:(Ljava/lang/String;)Ljava/lang/String;
8:   areturn
}

la méthode bridge, qui remplace la méthode de la classe de base "A", et non pas pas seulement en appelant une méthode avec un argument de type chaîne de caractères (#3), mais aussi en effectuant des opérations de type en "java.lang.String" (#2). Cela signifie que si vous exécutez code suivant, en ignorant l'avertissement "unchecked" du compilateur, le résultat sera une ClassCastException lancée par la méthode de pont :

A a = new B();
a.getT(new Object()));

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X