Szukam sposobu na przekazanie metody przez odniesienie. Rozumiem, że Java nie przekazuje metod jako parametrów, jednak chciałbym uzyskać alternatywę.
Powiedziano mi, że interfejsy są alternatywą dla przekazywania metod jako parametrów, ale nie rozumiem, jak interfejs może działać jako metoda przez odniesienie. Jeśli dobrze rozumiem, interfejs jest po prostu abstrakcyjnym zestawem metod, które nie są zdefiniowane. Nie chcę wysyłać interfejsu, który musi zostać zdefiniowany za każdym razem, ponieważ kilka różnych metod może wywoływać tę samą metodę z tymi samymi parametrami.
Chciałbym osiągnąć coś podobnego do tego:
public void setAllComponents(Component[] myComponentArray, Method myMethod) {
for (Component leaf : myComponentArray) {
if (leaf instanceof Container) { //recursive call if Container
Container node = (Container) leaf;
setAllComponents(node.getComponents(), myMethod);
} //end if node
myMethod(leaf);
} //end looping through components
}
przywołane, takie jak:
setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());
Odpowiedzi:
Edycja : od Java 8 wyrażenia lambda są dobrym rozwiązaniem, jak wskazały inne odpowiedzi . Poniższa odpowiedź została napisana dla Java 7 i wcześniejszych ...
Spójrz na wzór poleceń .
Edycja: jak zauważa Pete Kirkham , istnieje inny sposób na zrobienie tego za pomocą Odwiedzającego . Podejście oparte na odwiedzających jest nieco bardziej zaangażowane - wszystkie twoje węzły muszą być świadome
acceptVisitor()
metody przy pomocy odwiedzających - ale jeśli chcesz przejść przez bardziej złożony wykres obiektów, warto to zbadać.źródło
W Javie 8 możesz teraz łatwiej przekazać metodę za pomocą wyrażeń lambda i odwołań do metod. Po pierwsze, pewne tło: interfejs funkcjonalny to interfejs, który ma jedną i tylko jedną metodę abstrakcyjną, chociaż może zawierać dowolną liczbę metod domyślnych (nowość w Javie 8) i metod statycznych. Wyrażenie lambda może szybko zaimplementować metodę abstrakcyjną, bez całej niepotrzebnej składni potrzebnej, jeśli nie użyjesz wyrażenia lambda.
Bez wyrażeń lambda:
Z wyrażeniami lambda:
Oto fragment samouczka Java na temat wyrażeń Lambda :
Oto, w jaki sposób możesz „przekazać metodę” za pomocą wyrażenia lambda:
Klasę
C
można jeszcze bardziej skrócić, korzystając z takich referencji metod:źródło
::
operator), nie ma znaczenia, co to jest A.a.changeThing(component)
można zmienić na dowolną instrukcję lub blok kodu, o ile zwróci wartość void.Użyj
java.lang.reflect.Method
obiektu i wywołajinvoke
źródło
Od wersji Java 8 istnieje
Function<T, R>
interfejs ( dokumenty ), który ma metodęMożna go używać do przekazywania funkcji jako parametrów do innych funkcji. T jest typem wejściowym funkcji, R jest typem zwracanym.
W twoim przykładzie musisz przekazać funkcję, która pobiera
Component
typ jako dane wejściowe i nic nie zwraca -Void
. W tym przypadkuFunction<T, R>
nie jest najlepszym wyborem, ponieważ nie ma autoboxowania typu Void. Interfejs, którego szukasz, nazywa sięConsumer<T>
( docs ) metodąWyglądałoby to tak:
I nazwałbyś to przy użyciu referencji metod:
Zakładając, że zdefiniowałeś metody changeColor () i changeSize () w tej samej klasie.
Jeśli twoja metoda akceptuje więcej niż jeden parametr, możesz użyć
BiFunction<T, U, R>
- T i U są typami parametrów wejściowych, a R jest typem zwracanym. Są teżBiConsumer<T, U>
(dwa argumenty, brak typu zwracanego). Niestety dla 3 i więcej parametrów wejściowych musisz sam stworzyć interfejs. Na przykład:źródło
Najpierw zdefiniuj interfejs za pomocą metody, którą chcesz przekazać jako parametr
Zaimplementuj klasę za pomocą tej metody
// Wywołaj w ten sposób
Pozwala to przekazać cmd jako parametr i wywołać wywołanie metody zdefiniowane w interfejsie
źródło
Chociaż nie jest to jeszcze ważne dla Java 7 i niższych, uważam, że powinniśmy spojrzeć w przyszłość i przynajmniej rozpoznać zmiany, które pojawią się w nowych wersjach, takich jak Java 8.
Mianowicie, ta nowa wersja wprowadza JavaDa i odwołania do metod do Javy (wraz z nowymi interfejsami API , które są kolejnym prawidłowym rozwiązaniem tego problemu. Chociaż nadal wymagają interfejsu, nie są tworzone żadne nowe obiekty, a dodatkowe pliki klas nie muszą zanieczyszczać katalogów wyjściowych z powodu różnych obsługa przez JVM.
Oba smaki (lambda i odniesienie do metody) wymagają interfejsu dostępnego za pomocą jednej metody, której sygnatura jest używana:
Odtąd nazwy metod nie będą miały znaczenia. Tam, gdzie lambda jest akceptowana, jest również odniesienie do metody. Na przykład, aby użyć naszego podpisu tutaj:
Jest to zwykłe wywołanie interfejsu, aż do przejścia lambda 1 :
Spowoduje to wygenerowanie:
Odniesienia do metod są podobne. Dany:
i główne:
wynik byłby
real static method
. Odwołania do metod mogą być statyczne, instancja, niestatyczne z dowolnymi instancjami, a nawet konstruktorami . Dla konstruktoraClassName::new
byłoby coś podobnego .1 Dla niektórych nie jest to lambda, ponieważ ma skutki uboczne. Ilustruje to jednak użycie jednego w prostszy do wizualizacji sposób.
źródło
Ostatnim razem, gdy sprawdzałem, Java nie jest w stanie natywnie robić tego, co chcesz; musisz obejść takie ograniczenia, używając obejść. O ile mi się wydaje, interfejsy są alternatywą, ale nie dobrą alternatywą. Być może ktokolwiek ci to powiedział:
Które następnie wywołałeś za pomocą:
źródło
Jeśli nie potrzebujesz tych metod, aby coś zwrócić, możesz sprawić, że zwrócą obiekty Runnable.
Następnie użyj go w następujący sposób:
źródło
Nie znalazłem żadnego przykładu, który byłby dla mnie wystarczająco wyraźny, jak używać
java.util.function.Function
prostej metody jako funkcji parametru. Oto prosty przykład:Zasadniczo masz
Foo
obiekt z domyślnym konstruktorem. A,method
który zostanie wywołany jako parametr, zparametrisedMethod
którego jest typuFunction<String, Foo>
.Function<String, Foo>
oznacza, że funkcja przyjmujeString
parametr jako i zwraca aFoo
.Foo::Method
Odpowiadają jak lambdax -> Foo.method(x);
parametrisedMethod(Foo::method)
może być postrzegane jakox -> parametrisedMethod(Foo.method(x))
.apply("from a method")
to w zasadzie do zrobieniaparametrisedMethod(Foo.method("from a method"))
Który następnie zwróci w wyniku:
Przykład powinien być uruchomiony w obecnej postaci, możesz wypróbować bardziej skomplikowane rzeczy z powyższych odpowiedzi przy użyciu różnych klas i interfejsów.
źródło
Java ma mechanizm przekazywania nazwy i wywoływania jej. Jest to część mechanizmu odbicia. Twoja funkcja powinna przyjąć dodatkowy parametr metody klasy.
źródło
Nie jestem ekspertem od Java, ale rozwiązuję Twój problem w następujący sposób:
Definiuję parametr w moim specjalnym interfejsie
Wreszcie implementuję metodę getSearchText podczas wywoływania metody initialize .
źródło
Użyj wzorca Observer (czasami nazywanego również Wzorem Słuchacza):
new ComponentDelegate()...
deklaruje anonimowy typ implementujący interfejs.źródło
Oto podstawowy przykład:
Wynik:
źródło
Nie znalazłem tutaj żadnego rozwiązania, które pokazuje, jak przekazać metodę z powiązanymi z nią parametrami jako parametrem metody. Poniżej przedstawiono przykład, w jaki sposób można przekazać metodę z już powiązanymi wartościami parametrów.
Kolejny przykład pokazuje, jak przekazać metodę, która faktycznie coś zwraca
źródło
Przykład rozwiązania z refleksją, przekazana metoda musi być jawna
źródło
Doceniam powyższe odpowiedzi, ale udało mi się osiągnąć to samo zachowanie, stosując poniższą metodę; pomysł zapożyczony z wywołań JavaScript. Jestem otwarty na korekty, ale jak dotąd tak dobrze (w produkcji).
Chodzi o to, aby w sygnaturze użyć typu zwracanego przez funkcję, co oznacza, że wydajność musi być statyczna.
Poniżej znajduje się funkcja uruchamiająca proces z limitem czasu.
źródło