假设有一个Java类没有为其所有字段提供getter和setter,我必须使用:gen-class
扩展它并使用它们。
如何访问超类字段?
现在我想到的最快(也许是最干净的......)解决方案就是创建一个扩展我的超类的java类,然后扩展它,但是我想知道是否有另外一个听起来更多直接
谢谢!
答案 0 :(得分:3)
生成的类中的方法可以借助:exposes
gen-class
选项访问基类字段。 :exposes
期望一个映射,其中键是与基类字段名匹配的符号;值也是{:get getterName, :set setterName}
之类的地图。 Clojure自动生成那些getter和setter方法。它们可用于读取和修改基类字段。 gen-class
package fields;
class Base {
public String baseField = "base";
}
中记录了这一点。
此方法适用于公共和受保护的字段。它不适用于私人领域。
假设Java基类如下:
(ns fields.core
(:gen-class
:extends fields.Base
:methods [[bar [] String]
[baz [String] Object]]
:exposes { baseField { :get getField :set setField }}))
(defn -bar [this]
(str (.getField this) "-sub"))
(defn -baz [this val]
(.setField this val)
this)
(defn -main
[& args]
(println (.. (fields.core.) (bar)))
(println (.. (fields.core.) (baz "new-base") (bar))))
生成子类的Clojure代码是:
base-sub
new-base-sub
假设所有这些都是AOT编译并运行,输出为:
#include <stdio.h>
#include <cmqc.h>
#include <cmqxc.h>
#include "dte_mq.h"
#include <string.h>
#include <stdlib.h>
typedef struct tagDTE_QUEUE_DESCRIPTOR
{
MQHOBJ handle;
int IsSyncpointControled;
} DTE_QUEUE_DESCRIPTOR, *PDTE_QUEUE_DESCRIPTOR;
static MQHCONN sHConn = 0;
static MQLONG sCompCode = MQCC_OK;
static MQLONG sReason = MQRC_NONE;
static int sNumOpenQueues = 0;
static PDTE_QUEUE_DESCRIPTOR sQueues = NULL;
MQLONG OpenCode;
MQOD od = {MQOD_DEFAULT}; /* Object Descriptor */
MQMD md = {MQMD_DEFAULT};
MQPMO pmo = {MQPMO_DEFAULT};
MQLONG O_options;
MQGMO gmo = {MQGMO_DEFAULT};
/* MQCONNX options */
MQCNO Connect_options = {MQCNO_DEFAULT};
/* Client connection channel */
MQCD ClientConn = {MQCD_CLIENT_CONN_DEFAULT};
#define MAX_NUM_OPEN_QUEUES 10
DTE_MQ_RESULT dteMqSend(int qd, void *buf, int len)
{
printf("oleg\n");
/* memcpy(md.Format, MQFMT_STRING, MQ_FORMAT_LENGTH); */
md.MsgType = MQMT_DATAGRAM;
printf("oleg1\n");
memcpy(md.MsgId, MQMI_NONE, sizeof(md.MsgId));
printf("oleg2\n");
memcpy(md.CorrelId, MQCI_NONE, sizeof(md.CorrelId));
printf("oleg3\n");
memcpy(md.Format, MQFMT_STRING, (size_t)MQ_FORMAT_LENGTH);
printf("oleg4\n");
printf("QD is = %d\n",qd);
if(sQueues[qd].IsSyncpointControled)
pmo.Options |= MQPMO_SYNCPOINT;
printf("oleg5\n");
MQPUT(sHConn, sQueues[qd].handle, &md, &pmo, len, buf, &sCompCode, &sReason);
printf("MQput CC=%ld RC=%ld\n", sCompCode, sReason);
if (sCompCode != MQCC_OK) return DTE_MQR_FAILED;
return DTE_MQR_OK;
}
答案 1 :(得分:1)
我在理解所有细节方面遇到了一些麻烦,并决定试用最小版本。这是一个文件列表:
> d **/*.{clj,java}
-rw-rw-r-- 1 alan alan 501 Jun 29 17:11 project.clj
-rw-rw-r-- 1 alan alan 431 Jun 29 17:10 src/demo/core.clj
-rw-rw-r-- 1 alan alan 63 Jun 29 16:57 src-java/jpak/Base.java
以下是project.clj
(defproject demo "0.1.0-SNAPSHOT"
:description "demo code"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [
[org.clojure/clojure "1.8.0"]
[tupelo "0.9.55"]
]
:profiles {:dev {:dependencies [ [org.clojure/test.check "0.9.0"] ] }
:uberjar {:aot :all} }
:java-source-paths ["src-java"]
:aot [ demo.core ]
:main ^:skip-aot demo.core
:target-path "target/%s"
jvm-opts ["-Xms500m" "-Xmx500m" ]
)
和Java类:
package jpak;
public class Base {
public long answer = 41;
}
和我们的Clojure代码:
(ns demo.core
(:gen-class
:extends jpak.Base
:exposes {answer {:get getans :set setans}}
))
(defn -main
[& args]
(let [sub-obj (demo.core.) ; default name of subclass
old-answer (.getans sub-obj)
>> (.setans sub-obj (inc old-answer))
new-answer (.getans sub-obj) ]
(println "old answer = " old-answer)
(println "new answer = " new-answer)
))
我们可以使用lein run
来获取:
> lein run
old answer = 41
new answer = 42
版本2
如果Java变量answer
受到保护,则上述内容继续有效,但如果private
或“包受保护”(无限定符)则失败。这是有道理的,因为我们的子类在不同的包中。
此外,如果我给子类一个不同于默认值的名称,这是一个更清洁的,这是一个clojure命名空间名称“demo.core”:
(ns demo.core
(:gen-class
:name demo.Sub
:extends jpak.Base
:exposes {answer {:get getans :set setans}}
))
(defn -main
[& args]
(let [sub-obj (demo.Sub.) ; new name of subclass
old-answer (.getans sub-obj)
>> (.setans sub-obj (inc old-answer))
new-answer (.getans sub-obj)
]
(println "old answer = " old-answer)
(println "new answer = " new-answer)
))
版本3:访问private
成员值
在Java中,子类通常不能看到超类的私有成员变量;来自不同包装的“包装保护”成员也受到限制。这是讨厌的Java类:
package jpak;
public class Base {
private long answer = 41;
}
但是,Java具有覆盖private
访问限制的众所周知的能力,您甚至不需要子类!您需要做的就是使用反射。这是clojure版本:
(ns demo.break
(:import [jpak Base]))
(defn -main
[& args]
(let [base-obj (Base.)
class-obj (.getClass base-obj)
ans-field (.getDeclaredField class-obj "answer")
>> (.setAccessible ans-field true)
old-answer (.get ans-field base-obj)
>> (.set ans-field base-obj 42)
new-answer (.get ans-field base-obj)
]
(println "old answer = " old-answer)
(println "new answer = " new-answer)))
> lein run -m demo.break
old answer = 41
new answer = 42
See the docs for AccessibleObject here。请注意Field
&amp; Method
,包括反射期间返回的类,都包括在内。