2013-03-07 9 views
10

Una semplice interfaccia:GetMethods() restituisce non hanno definito in sede di attuazione un'interfaccia generica

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

L'output sarà:

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

solo myMethod viene stampato.

Ma se cambio l'interfaccia ad un generico uno:

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

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

Poi stranamente l'uscita sarà:

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

Perché dopo aver cambiato l'interfaccia per un generico porterà ad un altro Metodo con un tipo di parametro Oggetto?

risposta

6

Il primo metodo è uno bridge method, creato dal compilatore. Se si esegue il test dei metodi per 'isBridge()', è possibile filtrare i metodi 'errati' (inoltre esclude alcuni risultati strani che è possibile ottenere con i ritorni della covarianza).

Seguendo codice non stamperà il 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); 
} 
+0

Guardando in "che cosa è un metodo di ponte" ora. – StarPinkER

+1

Leggi questo tutorial, spiega tutto: http://docs.oracle.com/javase/tutorial/java/generics/erasure.html – Muel

2
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:Bridge methods

Citando il blog:

metodi ponte in Java sono metodi di sintesi, che sono necessari per implementa alcune delle funzionalità del linguaggio Java. I campioni più noti sono il tipo di ritorno covariante e un caso in generici quando la cancellazione degli argomenti del metodo di base differisce dal metodo effettivo richiamato.

aggiornamento del codice dall'alto blog:

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; 
     } 
    } 
} 

Sulla compilazione del codice sarà simile:

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 
} 

il metodo ponte, che sostituisce il metodo dalla classe di base "A ", non solo chiamando uno con argomento stringa (# 3), ma esegue anche il cast di tipo a "java.lang.String" (# 2). Ciò significa, che se si esegue codice seguente, ignorando avviso "incontrollato" del compilatore, il risultato sarà ClassCastException gettato dal metodo bridge:

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

+1 per il collegamento del blog. – StarPinkER

Problemi correlati