2010-04-27 10 views
15

Für dieses Beispiel Java-Klasse:Wie rufe ich überladene Java-Methoden in Clojure

package foo; 
public class TestInterop 
{ public String test(int i) 
    { return "Test(int)"; } 

    public String test(Object i) 
    { return "Test(Object)"; } 
} 

Wenn ich Clojure starten und versuchen, den Test (int) -Methode aufzurufen, der Test (Object) -Methode stattdessen aufgerufen wird, weil Clojure die ganze Zahl automatisch in ein java.lang.Integer-Objekt einfügt.

Wie erzwinge ich Clojure, die Test (int) -Methode aufzurufen?

user=> (.test (new foo.TestInterop) 10) 
"Test(Object)" 

Ich möchte AWT wie Component.add(Component comp, int index) Methoden aufrufen, sondern halten add(Component comp, Object constraints) anrufen, damit die Tasten auf meiner Symbolleiste immer in der falschen Reihenfolge angezeigt.

Antwort

14

Eine Diskussion findet gerade im #clojure Channel auf Freenode zu diesem Thema statt. Chris Houser (der eine Antwort schreiben wollte, aber letztendlich entschied, dass er zu beschäftigt war, um das zu tun) hat a Gist gepostet, was zeigt, was mit einer überladenen Methode boolean gegenüber Object passiert; Es stellt sich heraus, dass in einigen Szenarien zusätzlich zu einer (boolean ...) Umwandlung ein Typhinweis erforderlich ist. Die Diskussion war ziemlich aufschlussreich, und ein paar dunkle Ecken des Clojure-Kompilierungsprozesses wurden schön beleuchtet. (Siehe Links zum IRC-Protokoll unten.)

Wenn ein Objekt direkt in der Methodenaufrufform erstellt wird - (.foo (Foo.) ...), sagen Sie -, dass Typhinweis nicht notwendig ist; es ist ebenfalls nicht notwendig, wenn das Objekt als ein Wert für eine lokale in einem umschließenden let Formular erstellt wurde (siehe Update 2 unten und meine Version des Gist). Wenn das Objekt jedoch durch Var-Nachschlagen erhalten wird, ist ein Typhinweis erforderlich, der entweder auf dem Var selbst oder auf der Aufrufseite auf dem Symbol bereitgestellt werden kann, das verwendet wird, um auf den Var Bezug zu nehmen.

Die Java-Code aus dem Gist:

Und der Clojure Code:

(.foo (mypkg.Ugly.) 5) 
;=> "obj: 5" 

(.foo (mypkg.Ugly.) true) 
;=> "obj: true" 

(.foo (mypkg.Ugly.) (boolean true)) 
;=> "bool: true" 


(def u (mypkg.Ugly.)) 
(.foo u (boolean true)) 
;=> "obj: true" 

(.foo #^mypkg.Ugly u (boolean true)) 
;=> "bool: true" 

Hinweis, wie die Clojure Compiler einen Typ Hinweis auf u muss in die Lage einen direkten Methodenaufruf zu kompilieren . Ansonsten scheint ein reflektionsbasierter Code erzeugt zu werden, der scheinbar den Überblick verliert, dass das Argument auf dem Weg ein Primitiv sein soll.

Meine Ergänzungen folgen (und hier ist my fork of the above Gist).

;; renamed mypkg.Ugly to foo.TestInterop2 when doing my tests 
user> (let [t (foo.TestInterop2.)] 
     (.foo t (boolean true))) 
"bool: true" 

;;; type-hinting the Var 
user> (def #^foo.TestInterop2 x (foo.TestInterop2.)) 
#'user/x 
user> (.foo x (boolean true)) 
"bool: true" 

Das Thema wurde zum ersten Mal at this point gebracht. Chouser postete den Gist half an hour later, und die Diskussion wurde danach immer interessanter.

+0

Das erklärt, warum es immer in den Testprogrammen und nicht im echten Programm arbeitete. Ich habe den Tipp für den Anruf eingegeben und es funktioniert jetzt gut. Vielen Dank. Ich hatte eine Chance, ein Makro für dieses zu machen, da Sie die Klasse von der Variablen erhalten können, aber es sieht so aus, als ob die Typhinweise nicht Makro-ise sind. –

+0

Ich freue mich, das zu hören! Oh, und tatsächlich ist es möglich, Typhinweise in Makros zu behandeln - und manchmal kann ein gut entworfenes Makro schön angezeigten Code mit minimaler zusätzlicher Typisierung erzeugen. Sie könnten eine separate Frage zu diesem Thema stellen, wenn Sie Hilfe beim Schreiben benötigen. –

+0

Ich konnte dies nicht mit meinem Code arbeiten, obwohl meine Situation ein bisschen anders ist. Die Java-Methoden, die ich aufrufen möchte, sind JavaFX 'Application.launch'. Ich wünsche die statische 'launch' Methode mit dem Argument' Class 'und kann anscheinend keinen Typhinweis zu meinem Aufruf geben (ich habe viele Ansätze ausprobiert), der dazu führt, dass die richtige" launch "-Methode aufgerufen wird und ich bekomme" Class kann nicht in String umgewandelt werden "-Fehler. – Jason

8

Zahlen in Clojure werden im Allgemeinen eingerahmt (int => Integer), es sei denn, Sie fragen ausdrücklich nach Primitiven.

Here ist mehr Informationen über Primitive in Clojure.

+0

Das ist großartig. Vielen Dank. –

Verwandte Themen