Make a class that extends a class with overriding

2019-04-12 10:29发布

问题:

I've got pretty simple java code:

public class MessageListenerExample extends ListenerAdapter
{
    @Override
    public void onMessageReceived(MessageReceivedEvent event)
    {
        // do something with event
    }
}

However, I can't seem to understand how to turn that code into clojure code. The docs and articles are very confusing. I'd be happy to see more examples too. I'm also interested in using implements.

回答1:

Depending on what you need to do, a few options:

  1. If you really need to extend a class (other than Object) in Clojure, then you can do it using gen-class, see https://clojuredocs.org/clojure.core/gen-class. Preferably using ns macro, like
(ns your.class.Name
    :extends whatever.needs.to.be.Extended)

(defn -methodYouOverride   ; mind the dash - it's important
    [...] ...)

I wouldn't recommend going down this path unless absolutely necessary. Getting compilation right (including AOT compilation) is tricky. And in the end you still need to use Java interop to work with the objects of this class, so not sure it's worth the hassle, which brings me to:

  1. Code it in Java and use Java interop to work with it.

  2. If you actually need to create an instance of an object that implements a certain interface, then it's easier:

(reify
   InterfaceYouImplement
   (methodYouImplement [..] ..)

I use it around my code, it's really much nicer that coding in Java.



回答2:

You can use proxy to extend an existing Java class and also implement interfaces. For example:

(import '[java.awt.event ActionListener ActionEvent KeyAdapter KeyEvent])

(def listener
  (proxy
    ;; first vector contains superclass and interfaces that the created class should extend/implement
    [KeyAdapter ActionListener]
    ;; second vector contains arguments to superclass constructor
    []
    ;; below are all overriden/implemented methods
    (keyPressed [event]
      (println "Key pressed" event))
    (actionPerformed [action]
      (println "Action performed" action))))

(.keyPressed listener nil)
;; => Key pressed nil

(.actionPerformed listener nil)
;; => Action performed nil


回答3:

Just implement EventListener yourself, instead of using the adapter class that's there to make things more convenient for java programmers (but makes it harder for clojure programmers!). You'll receive an Event object, and you can check for yourself whether it's an instance of MessageReceivedEvent, just like the adapter would do for you.

Implementing an interface in Clojure is done via reify - see https://stackoverflow.com/a/8615002/625403 for an example.