@Suma Wie kann dies ein Duplikat sein, wenn die von Ihnen erwähnte Frage ein Jahr nach dieser gestellt wurde?
Ani
1
Java 8 hat eine ähnliche Funktion wie Delegierte. Es heißt Lambdas.
tbodt
4
@tbodt um genauer zu sein, Java 8 hat eine Funktion, die der von Delegierten sehr ähnlich ist. Es heißt funktionale Schnittstellen . Lambdas sind eine Möglichkeit, solche Delegateninstanzen (anonym) zu erstellen.
@nawfal, +1, aber um noch genauer zu sein, Java 7 und niedriger hat bereits eine Funktion, die der von Delegierten sehr ähnlich ist. Es heißt einfache Schnittstellen.
Pacerier
Antworten:
152
Nicht wirklich, nein.
Möglicherweise können Sie denselben Effekt erzielen, indem Sie mithilfe von Reflection Methodenobjekte abrufen, die Sie dann aufrufen können. Die andere Möglichkeit besteht darin, eine Schnittstelle mit einer einzelnen Methode zum Aufrufen oder Ausführen zu erstellen und diese dann zum Aufrufen der Methode zu instanziieren Ihr Interesse an (dh mit einer anonymen inneren Klasse).
Mit anonymen inneren Klassen können Sie sogar vermeiden, separate benannte Klassen zu deklarieren, und sie fast wie echte Delegatenfunktionen behandeln.
// JavapublicvoidSomeMethod(ISomeBehaviour pSomeBehaviour){...}...SomeMethod(newISomeBehaviour(){@OverridepublicvoidSomeFunction(){// your implementation}});
Dies sollte wahrscheinlich nur verwendet werden, wenn die Implementierung sehr spezifisch für den aktuellen Kontext ist und nicht von einer Wiederverwendung profitieren würde.
Und dann werden diese in Java 8 natürlich zu Lambda-Ausdrücken:
// Java 8SomeMethod(()->{/* your implementation */});
+1. Dies ist eine anständige Problemumgehung, und die Ausführlichkeit kann in Zukunft durch Wartbarkeit ausgeglichen werden.
Nawfal
Das ist großartig ... Derzeit arbeite ich an einem Projekt, bei dem ich aufgrund von Projektbeschränkungen keine Reflexion verwenden kann und diese Problemumgehung die Arbeit wunderbar erledigt :)
Jonathan Camarena
Hat Java eine I-Präfix-Namenskonvention für Schnittstellen? Ich habe das noch nie gesehen
Die neueste Version der Microsoft Visual J ++ - Entwicklungsumgebung unterstützt ein Sprachkonstrukt, das als Delegaten oder gebundene Methodenreferenzen bezeichnet wird . Dieses Konstrukt, und die neuen Keywords delegateund
multicastführten sie zu unterstützen, sind nicht Teil der Java TM
Programmiersprache, die von der angegeben ist Java Language Specification und geändert durch die inneren Klassen Spezifikation , die in der Dokumentation für die JDKTM 1.1 Software .
Es ist unwahrscheinlich, dass die Java-Programmiersprache dieses Konstrukt jemals enthält. Sun hat bereits 1996 sorgfältig überlegt, es zu übernehmen, um funktionierende Prototypen zu bauen und zu verwerfen. Unsere Schlussfolgerung war, dass gebundene Methodenreferenzen unnötig und für die Sprache schädlich sind. Diese Entscheidung wurde in Absprache mit Borland International getroffen, das bereits Erfahrungen mit gebundenen Methodenreferenzen in Delphi Object Pascal gesammelt hatte.
Wir glauben , gebundene Methode Referenzen sind nicht notwendig , da eine andere Design - Alternative, innere Klassen , gleiche oder bessere Funktionalität bereitstellt. Insbesondere unterstützen innere Klassen die Anforderungen der Ereignisbehandlung auf der Benutzeroberfläche vollständig und wurden verwendet, um eine Benutzeroberflächen-API zu implementieren, die mindestens so umfassend ist wie die Windows Foundation-Klassen.
Wir glauben, dass gebundene Methodenreferenzen schädlich sind, da sie die Einfachheit der Java-Programmiersprache und den allgegenwärtigen objektorientierten Charakter der APIs beeinträchtigen. Gebundene Methodenreferenzen führen auch zu Unregelmäßigkeiten in der Sprachsyntax und den Gültigkeitsbereichsregeln. Schließlich verwässern sie die Investition in VM-Technologien, da VMs zusätzliche und unterschiedliche Arten von Referenzen und Methodenverknüpfungen effizient verarbeiten müssen.
Wie in Patrick verlinkt , möchten Sie stattdessen innere Klassen verwenden.
SCdF
16
Großartiger Artikel. Ich LIEBE ihre Definition von "einfach": Java ist eine einfache Sprache wie in "Java muss einfach zu schreiben sein Compiler / VM für", während ignoriert wird "Java muss einfach zu schreiben / von einer Person zu lesen sein". . Erklärt viel.
Juozas Kontvainis
5
Ich denke nur, dass SUN einen großen Fehler gemacht hat. Das funktionale Paradigma hat sie einfach nicht überzeugt, und das ist alles.
Stephane Rolland
7
@Juozas: Python ist explizit so gestaltet, dass es von einer Person einfach geschrieben / gelesen werden kann, und es implementiert Lambda-Funktionen / Delegaten .
Stephane Rolland
5
Ersetzt durch einen archive.org-Link. Das ist auch wirklich dumm, Oracle.
Delegaten sind ein nützliches Konstrukt in ereignisbasierten Systemen. Im Wesentlichen sind Delegaten Objekte, die einen Methodenversand für ein bestimmtes Objekt codieren. Dieses Dokument zeigt, wie Java-Innenklassen eine allgemeinere Lösung für solche Probleme bieten.
Was ist ein Delegierter? Wirklich ist es einem Zeiger auf die Mitgliedsfunktion, wie sie in C ++ verwendet wird, sehr ähnlich. Ein Delegat enthält jedoch das Zielobjekt zusammen mit der aufzurufenden Methode. Im Idealfall wäre es schön sagen zu können:
obj.registerHandler (ano.methodOne);
..und dass die Methode methodOne ano aufgerufen wird, wenn ein bestimmtes Ereignis empfangen wird.
Dies erreicht die Delegiertenstruktur.
Java Inner Classes
Es wurde argumentiert, dass Java diese Funktionalität über anonyme innere Klassen bereitstellt und daher das zusätzliche Delegate-Konstrukt nicht benötigt.
Auf den ersten Blick scheint dies richtig, aber gleichzeitig ein Ärgernis zu sein. Da für viele Beispiele für die Ereignisverarbeitung die Einfachheit der Delegates-Syntax sehr attraktiv ist.
General Handler
Wenn die ereignisbasierte Programmierung jedoch umfassender eingesetzt wird, beispielsweise als Teil einer allgemeinen asynchronen Programmierumgebung, steht mehr auf dem Spiel.
In einer solchen allgemeinen Situation reicht es nicht aus, nur die Zielmethode und die Zielobjektinstanz einzuschließen. Im Allgemeinen sind möglicherweise andere Parameter erforderlich, die im Kontext festgelegt werden, wenn der Ereignishandler registriert wird.
In dieser allgemeineren Situation kann der Java-Ansatz eine sehr elegante Lösung bieten, insbesondere wenn er mit der Verwendung endgültiger Variablen kombiniert wird:
Beachten Sie, dass auf die endgültigen Variablen innerhalb der anonymen Klassenmethodendefinitionen zugegriffen werden kann. Lesen Sie diesen Code sorgfältig durch, um die Auswirkungen zu verstehen. Dies ist möglicherweise eine sehr leistungsfähige Technik. Beispielsweise kann es effektiv bei der Registrierung von Handlern in MiniDOM und in allgemeineren Situationen verwendet werden.
Im Gegensatz dazu bietet das Delegate-Konstrukt keine Lösung für diese allgemeinere Anforderung und sollte als solche als Redewendung abgelehnt werden, auf der Entwürfe basieren können.
Ich weiß, dass dieser Beitrag alt ist, aber Java 8 hat Lambdas hinzugefügt und das Konzept einer funktionalen Schnittstelle, bei der es sich um eine beliebige Schnittstelle mit nur einer Methode handelt. Zusammen bieten diese C # -Delegierten ähnliche Funktionen. Weitere Informationen finden Sie hier oder googeln Sie einfach Java Lambdas.
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
Das Schöne an dieser Redewendung ist, dass Sie an dem Punkt, an dem Sie den Delegator erstellen, überprüfen können, ob die delegierte Methode vorhanden ist und über die erforderliche Signatur verfügt (obwohl dies leider nicht zur Kompilierungszeit geschieht, obwohl ein FindBugs-Plug-In dies möglicherweise tut Hilfe hier), dann verwenden Sie es sicher, um an verschiedene Instanzen zu delegieren.
Ich habe Callback / Delegate-Unterstützung in Java mithilfe von Reflection implementiert. Details und Arbeitsquelle finden Sie auf meiner Website .
Wie es funktioniert
Es gibt eine Hauptklasse namens Callback mit einer verschachtelten Klasse namens WithParms. Die API, die den Rückruf benötigt, verwendet ein Callback-Objekt als Parameter und erstellt bei Bedarf einen Callback.WithParms als Methodenvariable. Da sehr viele Anwendungen dieses Objekts rekursiv sind, funktioniert dies sehr sauber.
Da die Leistung für mich immer noch eine hohe Priorität hat, wollte ich nicht verpflichtet sein, ein Wegwerfobjektarray zu erstellen, das die Parameter für jeden Aufruf enthält - schließlich kann es in einer großen Datenstruktur Tausende von Elementen geben und in einer Nachrichtenverarbeitung In diesem Szenario könnten wir am Ende Tausende von Datenstrukturen pro Sekunde verarbeiten.
Um threadsicher zu sein, muss das Parameterarray für jeden Aufruf der API-Methode eindeutig vorhanden sein, und aus Effizienzgründen sollte für jeden Aufruf des Rückrufs dasselbe verwendet werden. Ich brauchte ein zweites Objekt, dessen Erstellung billig wäre, um den Rückruf mit einem Parameterarray zum Aufrufen zu binden. In einigen Szenarien verfügt der Aufrufer jedoch aus anderen Gründen bereits über ein Parameterarray. Aus diesen beiden Gründen gehört das Parameterarray nicht zum Callback-Objekt. Auch die Wahl des Aufrufs (Übergabe der Parameter als Array oder als einzelne Objekte) liegt in den Händen der API, die den Rückruf verwendet, um den Aufruf zu verwenden, der für das Innenleben am besten geeignet ist.
Die verschachtelte WithParms-Klasse ist also optional und dient zwei Zwecken: Sie enthält das für die Rückrufaufrufe erforderliche Parameterobjektarray und bietet 10 überladene invoke () -Methoden (mit 1 bis 10 Parametern), die das Parameterarray laden und dann Rufen Sie das Rückrufziel auf.
Es folgt ein Beispiel für die Verwendung eines Rückrufs zur Verarbeitung der Dateien in einem Verzeichnisbaum. Dies ist ein erster Validierungsdurchlauf, bei dem nur die zu verarbeitenden Dateien gezählt werden und sichergestellt wird, dass keine eine vorgegebene maximale Größe überschreitet. In diesem Fall erstellen wir den Rückruf nur inline mit dem API-Aufruf. Wir reflektieren die Zielmethode jedoch als statischen Wert, sodass die Reflexion nicht jedes Mal erfolgt.
staticprivatefinalMethod COUNT =Callback.getMethod(Xxx.class,"callback_count",true,File.class,File.class);...IoUtil.processDirectory(root,newCallback(this,COUNT),selector);...privatevoid callback_count(File dir,File fil){if(fil!=null){// file is null for processing a directory
fileTotal++;if(fil.length()>fileSizeLimit){thrownewAbort("Failed","File size exceeds maximum of "+TextUtil.formatNumber(fileSizeLimit)+" bytes: "+fil);}}
progress("Counting",dir,fileTotal);}
IoUtil.processDirectory ():
/**
* Process a directory using callbacks. To interrupt, the callback must throw an (unchecked) exception.
* Subdirectories are processed only if the selector is null or selects the directories, and are done
* after the files in any given directory. When the callback is invoked for a directory, the file
* argument is null;
* <p>
* The callback signature is:
* <pre> void callback(File dir, File ent);</pre>
* <p>
* @return The number of files processed.
*/staticpublicint processDirectory(File dir,Callback cbk,FileSelector sel){return _processDirectory(dir,newCallback.WithParms(cbk,2),sel);}staticprivateint _processDirectory(File dir,Callback.WithParms cbk,FileSelector sel){int cnt=0;if(!dir.isDirectory()){if(sel==null|| sel.accept(dir)){ cbk.invoke(dir.getParent(),dir); cnt++;}}else{
cbk.invoke(dir,(Object[])null);File[] lst=(sel==null? dir.listFiles(): dir.listFiles(sel));if(lst!=null){for(int xa=0; xa<lst.length; xa++){File ent=lst[xa];if(!ent.isDirectory()){
cbk.invoke(dir,ent);
lst[xa]=null;
cnt++;}}for(int xa=0; xa<lst.length; xa++){File ent=lst[xa];if(ent!=null){ cnt+=_processDirectory(ent,cbk,sel);}}}}return cnt;}
Dieses Beispiel zeigt die Schönheit dieses Ansatzes: Die anwendungsspezifische Logik wird in den Rückruf abstrahiert, und die Plackerei, einen Verzeichnisbaum rekursiv zu durchlaufen, ist in einer vollständig wiederverwendbaren statischen Dienstprogrammmethode versteckt. Und wir müssen nicht wiederholt den Preis für die Definition und Implementierung einer Schnittstelle für jede neue Verwendung bezahlen. Natürlich das Argument für eine Schnittstelle ist dass es viel expliziter ist, was implementiert werden soll (erzwungen, nicht einfach dokumentiert) - aber in der Praxis habe ich es nicht als Problem empfunden, die Rückrufdefinition richtig zu machen.
Das Definieren und Implementieren einer Schnittstelle ist nicht wirklich so schlecht (es sei denn, Sie verteilen wie ich Applets, bei denen das Vermeiden des Erstellens zusätzlicher Klassen tatsächlich wichtig ist), aber dies ist wirklich der Fall, wenn Sie mehrere Rückrufe in einer einzelnen Klasse haben. Es ist nicht nur gezwungen, sie jeweils in eine separate innere Klasse zu verschieben, was den Overhead in der bereitgestellten Anwendung erhöht, sondern es ist geradezu mühsam zu programmieren, und der gesamte Code auf der Kesselplatte ist wirklich nur "Rauschen".
Ja und Nein, aber das Delegatenmuster in Java könnte so gedacht werden. In diesem Video-Tutorial geht es um den Datenaustausch zwischen Aktivitätsfragmenten. Das Delegat-Sorta-Muster wird über Schnittstellen delegiert.
Es hat kein explizites delegateSchlüsselwort als C #, aber Sie können in Java 8 ähnliche Ergebnisse erzielen, indem Sie eine funktionale Schnittstelle (dh eine beliebige Schnittstelle mit genau einer Methode) und Lambda verwenden:
privateinterfaceSingleFunc{void printMe();}publicstaticvoid main(String[] args){SingleFunc sf =()->{System.out.println("Hello, I am a simple single func.");};SingleFunc sfComplex =()->{System.out.println("Hello, I am a COMPLEX single func.");};
delegate(sf);
delegate(sfComplex);}privatestaticvoid delegate(SingleFunc f){
f.printMe();}
Jedes neue Objekt vom Typ SingleFuncmuss implementiert werden printMe(), sodass es sicher an eine andere Methode (z. B. delegate(SingleFunc)) übergeben werden kann, um die printMe()Methode aufzurufen .
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert.
StackFlowed
2
@StackFlowed Entfernen Sie den Link, und was bekommen Sie? Ein Beitrag mit Informationen. Stimmen Sie ab, um zu behalten.
Scimonster
1
@ Scimonster was würde passieren, wenn der Link nicht mehr gültig ist?
StackFlowed
@StackFlowed Es gibt immer noch eine Antwort - verwenden Sie einen Java-Proxy.
Scimonster
dann könnte es als Kommentar hinterlassen werden?
StackFlowed
0
Nein, aber es hat intern ein ähnliches Verhalten.
In C # werden Delegaten verwendet, um einen separaten Einstiegspunkt zu erstellen, und sie funktionieren ähnlich wie ein Funktionszeiger.
In Java gibt es keinen Funktionszeiger (im oberen Bereich), aber intern muss Java dasselbe tun, um diese Ziele zu erreichen.
Zum Erstellen von Threads in Java ist beispielsweise eine Klasse erforderlich, die Thread erweitert oder Runnable implementiert, da eine Klassenobjektvariable als Speicherortzeiger verwendet werden kann.
Nein, Java hat diese erstaunliche Funktion nicht. Sie können es jedoch manuell mithilfe des Beobachtermusters erstellen. Hier ein Beispiel:
Schreiben Sie einen C # -Delegierten in Java
Der beschriebene Code bietet viele der Vorteile von C # -Delegierten. Statische oder dynamische Methoden können einheitlich behandelt werden. Die Komplexität beim Aufrufen von Methoden durch Reflektion wird reduziert und der Code ist wiederverwendbar, da keine zusätzlichen Klassen im Benutzercode erforderlich sind. Beachten Sie, dass wir eine alternative Convenience-Version von invoke aufrufen, bei der eine Methode mit einem Parameter aufgerufen werden kann, ohne ein Objektarray zu erstellen. Java-Code unten:
Java hat keine Delegierten und ist stolz darauf :). Nach dem, was ich hier gelesen habe, habe ich im Wesentlichen zwei Möglichkeiten gefunden, Delegierte zu fälschen: 1. Reflexion; 2. innere Klasse
Reflexionen sind langsam! Die innere Klasse behandelt nicht den einfachsten Anwendungsfall: die Sortierfunktion. Sie möchten nicht auf Details eingehen, aber die Lösung mit der inneren Klasse besteht im Wesentlichen darin, eine Wrapper-Klasse für ein Array von Ganzzahlen zu erstellen, die in aufsteigender Reihenfolge sortiert werden sollen, und eine Klasse für ein Array von Ganzzahlen, die in absteigender Reihenfolge sortiert werden sollen.
Antworten:
Nicht wirklich, nein.
Möglicherweise können Sie denselben Effekt erzielen, indem Sie mithilfe von Reflection Methodenobjekte abrufen, die Sie dann aufrufen können. Die andere Möglichkeit besteht darin, eine Schnittstelle mit einer einzelnen Methode zum Aufrufen oder Ausführen zu erstellen und diese dann zum Aufrufen der Methode zu instanziieren Ihr Interesse an (dh mit einer anonymen inneren Klasse).
Vielleicht finden Sie diesen Artikel auch interessant / nützlich: Ein Java-Programmierer betrachtet C # -Delegierte (@ archive.org)
quelle
Je nachdem, was Sie genau meinen, können Sie mithilfe des Strategiemusters einen ähnlichen Effekt erzielen (eine Methode weitergeben).
Anstelle einer Zeile wie dieser, die eine benannte Methodensignatur deklariert:
Deklarieren Sie eine Schnittstelle:
Definieren Sie für konkrete Implementierungen der Methode eine Klasse, die das Verhalten implementiert:
SomeFunction
Verwenden SieISomeBehaviour
stattdessen überall dort, wo Sie einen Delegaten in C # gehabt hätten , eine Referenz:Mit anonymen inneren Klassen können Sie sogar vermeiden, separate benannte Klassen zu deklarieren, und sie fast wie echte Delegatenfunktionen behandeln.
Dies sollte wahrscheinlich nur verwendet werden, wenn die Implementierung sehr spezifisch für den aktuellen Kontext ist und nicht von einer Wiederverwendung profitieren würde.
Und dann werden diese in Java 8 natürlich zu Lambda-Ausdrücken:
quelle
Kurzgeschichte: nein .
quelle
Haben Sie lesen diese :
quelle
Ich weiß, dass dieser Beitrag alt ist, aber Java 8 hat Lambdas hinzugefügt und das Konzept einer funktionalen Schnittstelle, bei der es sich um eine beliebige Schnittstelle mit nur einer Methode handelt. Zusammen bieten diese C # -Delegierten ähnliche Funktionen. Weitere Informationen finden Sie hier oder googeln Sie einfach Java Lambdas. http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
quelle
Nein, aber sie können mit Proxies und Reflexionen gefälscht werden:
Das Schöne an dieser Redewendung ist, dass Sie an dem Punkt, an dem Sie den Delegator erstellen, überprüfen können, ob die delegierte Methode vorhanden ist und über die erforderliche Signatur verfügt (obwohl dies leider nicht zur Kompilierungszeit geschieht, obwohl ein FindBugs-Plug-In dies möglicherweise tut Hilfe hier), dann verwenden Sie es sicher, um an verschiedene Instanzen zu delegieren.
Weitere Tests und Implementierungen finden Sie im Karg-Code auf Github .
quelle
Ich habe Callback / Delegate-Unterstützung in Java mithilfe von Reflection implementiert. Details und Arbeitsquelle finden Sie auf meiner Website .
Wie es funktioniert
Es gibt eine Hauptklasse namens Callback mit einer verschachtelten Klasse namens WithParms. Die API, die den Rückruf benötigt, verwendet ein Callback-Objekt als Parameter und erstellt bei Bedarf einen Callback.WithParms als Methodenvariable. Da sehr viele Anwendungen dieses Objekts rekursiv sind, funktioniert dies sehr sauber.
Da die Leistung für mich immer noch eine hohe Priorität hat, wollte ich nicht verpflichtet sein, ein Wegwerfobjektarray zu erstellen, das die Parameter für jeden Aufruf enthält - schließlich kann es in einer großen Datenstruktur Tausende von Elementen geben und in einer Nachrichtenverarbeitung In diesem Szenario könnten wir am Ende Tausende von Datenstrukturen pro Sekunde verarbeiten.
Um threadsicher zu sein, muss das Parameterarray für jeden Aufruf der API-Methode eindeutig vorhanden sein, und aus Effizienzgründen sollte für jeden Aufruf des Rückrufs dasselbe verwendet werden. Ich brauchte ein zweites Objekt, dessen Erstellung billig wäre, um den Rückruf mit einem Parameterarray zum Aufrufen zu binden. In einigen Szenarien verfügt der Aufrufer jedoch aus anderen Gründen bereits über ein Parameterarray. Aus diesen beiden Gründen gehört das Parameterarray nicht zum Callback-Objekt. Auch die Wahl des Aufrufs (Übergabe der Parameter als Array oder als einzelne Objekte) liegt in den Händen der API, die den Rückruf verwendet, um den Aufruf zu verwenden, der für das Innenleben am besten geeignet ist.
Die verschachtelte WithParms-Klasse ist also optional und dient zwei Zwecken: Sie enthält das für die Rückrufaufrufe erforderliche Parameterobjektarray und bietet 10 überladene invoke () -Methoden (mit 1 bis 10 Parametern), die das Parameterarray laden und dann Rufen Sie das Rückrufziel auf.
Es folgt ein Beispiel für die Verwendung eines Rückrufs zur Verarbeitung der Dateien in einem Verzeichnisbaum. Dies ist ein erster Validierungsdurchlauf, bei dem nur die zu verarbeitenden Dateien gezählt werden und sichergestellt wird, dass keine eine vorgegebene maximale Größe überschreitet. In diesem Fall erstellen wir den Rückruf nur inline mit dem API-Aufruf. Wir reflektieren die Zielmethode jedoch als statischen Wert, sodass die Reflexion nicht jedes Mal erfolgt.
IoUtil.processDirectory ():
Dieses Beispiel zeigt die Schönheit dieses Ansatzes: Die anwendungsspezifische Logik wird in den Rückruf abstrahiert, und die Plackerei, einen Verzeichnisbaum rekursiv zu durchlaufen, ist in einer vollständig wiederverwendbaren statischen Dienstprogrammmethode versteckt. Und wir müssen nicht wiederholt den Preis für die Definition und Implementierung einer Schnittstelle für jede neue Verwendung bezahlen. Natürlich das Argument für eine Schnittstelle ist dass es viel expliziter ist, was implementiert werden soll (erzwungen, nicht einfach dokumentiert) - aber in der Praxis habe ich es nicht als Problem empfunden, die Rückrufdefinition richtig zu machen.
Das Definieren und Implementieren einer Schnittstelle ist nicht wirklich so schlecht (es sei denn, Sie verteilen wie ich Applets, bei denen das Vermeiden des Erstellens zusätzlicher Klassen tatsächlich wichtig ist), aber dies ist wirklich der Fall, wenn Sie mehrere Rückrufe in einer einzelnen Klasse haben. Es ist nicht nur gezwungen, sie jeweils in eine separate innere Klasse zu verschieben, was den Overhead in der bereitgestellten Anwendung erhöht, sondern es ist geradezu mühsam zu programmieren, und der gesamte Code auf der Kesselplatte ist wirklich nur "Rauschen".
quelle
Ja und Nein, aber das Delegatenmuster in Java könnte so gedacht werden. In diesem Video-Tutorial geht es um den Datenaustausch zwischen Aktivitätsfragmenten. Das Delegat-Sorta-Muster wird über Schnittstellen delegiert.
quelle
Es hat kein explizites
delegate
Schlüsselwort als C #, aber Sie können in Java 8 ähnliche Ergebnisse erzielen, indem Sie eine funktionale Schnittstelle (dh eine beliebige Schnittstelle mit genau einer Methode) und Lambda verwenden:Jedes neue Objekt vom Typ
SingleFunc
muss implementiert werdenprintMe()
, sodass es sicher an eine andere Methode (z. B.delegate(SingleFunc)
) übergeben werden kann, um dieprintMe()
Methode aufzurufen .quelle
Es ist zwar bei weitem nicht so sauber, aber Sie könnten so etwas wie C # -Delegierte mit einem Java- Proxy implementieren .
quelle
Nein, aber es hat intern ein ähnliches Verhalten.
In C # werden Delegaten verwendet, um einen separaten Einstiegspunkt zu erstellen, und sie funktionieren ähnlich wie ein Funktionszeiger.
In Java gibt es keinen Funktionszeiger (im oberen Bereich), aber intern muss Java dasselbe tun, um diese Ziele zu erreichen.
Zum Erstellen von Threads in Java ist beispielsweise eine Klasse erforderlich, die Thread erweitert oder Runnable implementiert, da eine Klassenobjektvariable als Speicherortzeiger verwendet werden kann.
quelle
Nein, Java hat diese erstaunliche Funktion nicht. Sie können es jedoch manuell mithilfe des Beobachtermusters erstellen. Hier ein Beispiel: Schreiben Sie einen C # -Delegierten in Java
quelle
Der beschriebene Code bietet viele der Vorteile von C # -Delegierten. Statische oder dynamische Methoden können einheitlich behandelt werden. Die Komplexität beim Aufrufen von Methoden durch Reflektion wird reduziert und der Code ist wiederverwendbar, da keine zusätzlichen Klassen im Benutzercode erforderlich sind. Beachten Sie, dass wir eine alternative Convenience-Version von invoke aufrufen, bei der eine Methode mit einem Parameter aufgerufen werden kann, ohne ein Objektarray zu erstellen. Java-Code unten:
quelle
Java hat keine Delegierten und ist stolz darauf :). Nach dem, was ich hier gelesen habe, habe ich im Wesentlichen zwei Möglichkeiten gefunden, Delegierte zu fälschen: 1. Reflexion; 2. innere Klasse
Reflexionen sind langsam! Die innere Klasse behandelt nicht den einfachsten Anwendungsfall: die Sortierfunktion. Sie möchten nicht auf Details eingehen, aber die Lösung mit der inneren Klasse besteht im Wesentlichen darin, eine Wrapper-Klasse für ein Array von Ganzzahlen zu erstellen, die in aufsteigender Reihenfolge sortiert werden sollen, und eine Klasse für ein Array von Ganzzahlen, die in absteigender Reihenfolge sortiert werden sollen.
quelle