2017-01-27 10 views
0

Ich möchte eine Methode schreiben, die eine angegebene Methode für ein geeignetes Objekt aufruft.
Der Vorbehalt ist, dass ich dies tun möchte, ohne die Klassen zu ändern (z. B. Implementierungsschnittstellen) von wo ich die Methode nenne.Java7: Was entspricht der Angabe von Methodenreferenzen in einem Funktionsaufruf?

Ich fand, was ich in Funktionszeiger in C suchte, aber nichts für Java 7 noch.

Hier einige Pseudo-Code:

public class A { 
    ... constructor ... 

    public String aToString(){ 
     return "A"; 
    } 
} 

public class B { 
    ... constructor ... 

    public String bToString(){ 
     return "B"; 
    } 
} 
/* T::<String>mymethod stands for "Method with identifier 'mymethod' 
* in Class T with return type String" 
*/ 
public class ServiceClass { 
    public static void genericToString(Collection<T> c, 
             MethodPointer T::<String>mymethod){ 
     for(int i=0,i<c.length,i++) { 
      System.out.println(c.get(i).mymethod()); 

     } 
    } 

    public static void main(){ 
     ArrayList<A> listA = new ArrayList<A>(); 
     listA.add(new A()); 
     ServiceClass.genericToStringOutput(listA, A::<String>aToString); 

     ArrayList<B> listB = new ArrayList<B>(); 
     listB.add(new B()); 
     ServiceClass.genericToStringOutput(listB, B::<String>bToString); 
    } 
} 

Gibt es eine Möglichkeit 7 so etwas wie dies in Java zu erreichen? Die einzige Einschränkung besteht darin, dass Klasse A und B sich nicht ändern können.

Bonuspunkte, wenn Typen nicht vom Compiler ausgeblendet werden.

+1

Sie könnten 8 ... –

+3

zu Java wechseln möchten, können Sie Anbieter eine 'Funktion ', entweder Ihre eigenen Schreiben "Funktion" -Schnittstelle oder [die von Guava] verwenden (https://google.github.io/guava/releases/19.0/api/docs/com/google/common/base/Function.html). –

Antwort

2

entweder eine Function Schnittstelle machen oder wählen und passieren, dass in:

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.List; 

class A { 
    public String aToString() { 
    return "A"; 
    } 
} 

class B { 
    public String bToString() { 
    return "B"; 
    } 
} 

interface Function<IN, OUT> { 
    OUT apply(IN input);//see guava for a prefab version of this 
} 

class ServiceClass { 
    public static <T> void genericToString(Collection<T> c, Function<T, String> converter) { 
    for (final T element : c) { 
     System.out.println(converter.apply(element)); 
    } 
    } 

    public static void main() { 
    List<A> listA = new ArrayList<>(); 
    listA.add(new A()); 
    ServiceClass.genericToString(listA, new Function<A, String>() {//the java 7 way 
     @Override 
     public String apply(final A input) { 
     return input.aToString(); 
     } 
    }); 

    List<B> listB = new ArrayList<>(); 
    listB.add(new B()); 
    ServiceClass.genericToString(listB, B::bToString);//the java 8 way 
    } 
} 
+0

Vielen Dank für diese Lösung. Es funktioniert wie ein Charme und ist schön generisch. – Phyr

-2

In Java 7, Sie sind für so etwas wie

import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.util.ArrayList; 
import java.util.Collection; 

public class ServiceClass<T> { 

    public void genericToString(Collection<T> c, Method m) 
     throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{ 
     for(T e : c) { 
      System.out.println(m.invoke(e)); 
     } 
    } 

    public static void main(){ 
     Method m; 
     ArrayList<A> listA = new ArrayList<A>(); 
     listA.add(new A()); 
     m = new A().getClass().getMethod("aToString", new Class[]{}); 
     ServiceClass.genericToStringOutput(listA, m); 

     ArrayList<B> listB = new ArrayList<B>(); 
     listB.add(new B()); 
     m = new B().getClass().getMethod("bToString", new Class[]{}); 
     ServiceClass.genericToStringOutput(listB, m); 
    } 
} 
+0

Sie * können * Reflexion verwenden, um dies zu tun, aber Sie sollten nicht. Reflection kann zur Kompilierzeit nicht überprüft werden und bietet viel mehr Möglichkeiten für Laufzeitfehler. – VGR

+0

So wie es ohne Reflexion und ohne die Definition der Klassen A und B zu ändern? –

+0

Wie die anderen Antworten vorschlagen, erstellen Sie eine separate Schnittstelle, die java.util.function.Function ähnlich ist, und wickeln Sie einen Aufruf der Methode jeder Klasse in einer anonymen Implementierung dieser Schnittstelle um. – VGR

1

In Java 7, entsprechende Code suchen, um etwas ähnliches Verfahren Referenzen zu haben ist folgende: Zuerst definieren wir eine Schnittstelle für unsere Referenz (nichts anderes im Vergleich zu Java 8):

public interface MethodPointer<T> { 
    String invoke(T arg); 
} 

Dann benutzen wir es:

public class ServiceClass { 
public static void genericToString(Collection<T> c, 
            MethodPointer<T> mymethod) { 
    for(int i=0,i<c.length,i++) { 
     System.out.println(mymethod.invoke(c.get(i))); 
    } 
} 

public static void main() { 
    ArrayList<A> listA = new ArrayList<A>(); 
    listA.add(new A()); 
    ServiceClass.genericToStringOutput(listA, new MethodPointer<A>() { 
     @Override public String invoke(A arg) { 
     return arg.toString(); 
     } 
    }); 

    ArrayList<B> listB = new ArrayList<B>(); 
    listB.add(new B()); 
    ServiceClass.genericToStringOutput(listB, new MethodPointer<B>() { 
     @Override public String invoke(B arg) { 
     return arg.toDetailedString() // <- note that it's not just toString() 
     } 
    }); 
} 

}

Verwandte Themen