Dans cet article, nous utilisons ABCL (Armed-Bear-Common Lisp), qui est l'un de nos systèmes de traitement Common Lisp et fonctionne sur JVM, pour faire fonctionner des classes et des méthodes écrites en langage Java. La procédure de base est illustrée ci-dessous.
** "Seule l'API pour Java est fournie, mais je souhaite utiliser l'application avec Common Lisp (ci-après dénommée CL)!" **. Il y a, non? Ouais, j'en suis sûr.
** "Mais il n'y a presque pas de documents japonais, je ne suis pas très bon en Clojure, et c'est difficile d'écrire autre que Lisp!" ** Je ne sais pas si quelqu'un est là, mais cet article est basé sur ABCL pour ces personnes. Ceci est un article qui décrit les bases de l'intérieur.
Dans cet article, nous n'appellerons que des méthodes Java simples de CL. J'écrirai les détails dans un article séparé, donc si vous le recherchez, vous risquez de ne rien obtenir, il est donc recommandé de revenir au navigateur.
C'était le plus (ou le seul) utile.
Au début, je parlais de cela, mais je n'en comprenais pas vraiment le sens et j'en étais accro.
Si vous vous perdez, il peut être judicieux de consulter le code source.
Les informations sur ABCL sont ici, non?
Malheureusement, il n'y a pas de document pour ceux qui ne peuvent lire que le japonais ou ne le savent pas. Il n'est pas rédigé dans un anglais aussi difficile, alors faites de votre mieux pour le lire.
J'espère que cet article vous donnera une idée des bases!
Maintenant, je vais expliquer les spécifications ABCL pour appeler Java à partir de Common Lisp.
Au cas où, jetons un coup d'œil à cet environnement d'exécution. Cela devrait probablement également fonctionner sur d'autres plates-formes. Je ne l'ai pas vérifié. .. ..
Tout d'abord, je vais expliquer comment appeler une méthode statique. Le code Java simple utilisé pour cet appel est le suivant.
Calc.java
public class Calc {
public static int addTwoNumbers(int a, int b) {
return a + b;
}
}
En tant que méthode statique de la classe Calc, elle effectue un simple travail ** de prise de deux arguments de type entier et de retour de la somme de ceux-ci comme valeur de retour **. Appelons cette méthode addTwoNumbers à partir de Common Lisp. Le code ressemble à ceci (↓)
calc.lisp
(defun add-two-num (num1 num2)
(let ((result (jstatic "addTwoNumbers" "Calc" num1 num2)))
result))
jstatic est une fonction intégrée pour appeler des méthodes statiques Java. Le premier argument est le nom de la méthode à appeler (chaîne de caractères) **, le deuxième argument est la classe à laquelle appartient la méthode cible **, et le troisième argument et les suivants sont les ** arguments de méthode **. Lorsqu'il est évalué, le résultat de l'exécution de la méthode est retourné, il est lié au résultat et il est sorti à la fin.
Même si vous regardez l'exemple de programme, seul celui-ci est écrit, mais bien sûr le code Java ne peut pas être appelé tel quel, alors compilez-le et passez-le via le chemin de classe. Je ne sais pas grand-chose à ce sujet, donc si je l'écris pour les gens,
$ javac Calc.java
$ ls
Calc.class Calc.java calc.lisp
Si cela devient, c'est un succès. Si la compilation échoue, quelque chose ne va pas et veuillez vérifier à nouveau. En disant cela, il ne peut y avoir aucune erreur avec cette longueur de code.
Passons à REPL et appelons-le!
CL-USER> (load "/Path/to/calc.lisp")
T
CL-USER> (add-to-classpath "/Path/to/Calc.java/")
("/Path/to/java-class")
CL-USER> (add-two-num 2 3)
5
CL-UER> (add-two-num -1 9)
8
Vous pouvez l'appeler correctement! add-to-classpath est la fonction intégrée d'ABCL pour transmettre les chemins aux fichiers de classe Java. En Java, vous pouvez passer le chemin de la classe, mais c'est plus facile à lire dynamiquement (vue personnelle).
Je ne suis pas si heureux de pouvoir appeler uniquement la méthode Static, alors vérifions la répartition dynamique de la méthode. Le code utilisé pour cet essai est le suivant.
Hero.java
public class Hero {
private int hp;
private int mp;
public Hero() {
hp = 100;
mp = 100;
}
public void getDamage(int damage){
hp -= damage;
}
public void useMagic(int consumption){
mp -= consumption;
}
public String showStatus(){
return "HP: "+hp+", MP: "+mp;
}
public static void main(String[] argv){
Hero hero = new Hero();
}
}
Il y a un héros qui a "HP: 100" et "MP: 100" à sa naissance. Il subit un certain nombre de dégâts lorsqu'il est attaqué et consomme des PM lors de l'utilisation de la magie. Si vous vérifiez l'état, les HP et MP restants seront affichés.
Veuillez laisser de côté ce type de conception de classe et pensez que vous avez défini une classe comme celle-ci.
hero.lisp
(add-to-classpath "/Path/to/java-class-file")
(defun hero-status ()
(let* ((hero-class (jclass "Hero"))
(hero-instance (jnew (jconstructor "Hero")))
(method (jmethod hero-class "showStatus"))
(result (jcall method hero-instance)))
result))
Tout d'abord, instanciez cette classe Hero et appelez la méthode showStatus. L'état initial "HP: 100, MP: 100" doit être émis.
Auparavant, j'ai évalué add-to-classpath au niveau supérieur de REPL, mais bien sûr, si vous le mettez dans le fichier Lisp, il sera exécuté au moment du chargement.
jclass prend une chaîne comme argument et renvoie une référence de classe Java avec le nom de cette chaîne. Ce qui est renvoyé ici est un objet de classe, pas une instance.
jnew prend un objet constructeur comme argument et crée une instance. Veuillez noter qu'il ne peut être instancié que si l'objet constructeur est acquis par (jconstructor "nom de classe (chaîne de caractères)") [^ Note 1].
jmethod récupère la méthode à appeler en tant qu'objet. Transmettez l'objet de classe Java et le nom de la méthode, et si nécessaire, le type d'argument class [^ Note 2].
Enfin, passez l'objet méthode acquis précédemment et l'objet instance à jcall et exécutez la méthode.
Lorsque vous l'exécutez réellement, cela devrait ressembler à ce qui suit.
CL-USER> (load "/Path/to/hero.lisp")
T
CL-USER> (hero-status)
"HP: 100, MP: 100"
Ensuite, après avoir utilisé la méthode de réduction HP et la méthode de réduction MP, exécutez la méthode de confirmation d'état. Les deux méthodes soustraire la valeur en passant la valeur à réduire à l'argument.
L'expression Lisp pour appeler ressemble à ceci.
hero-extend.lisp
(defun extended-hero-status (hp mp)
(let* ((hero-class (jclass "Hero"))
(hero-instance (jnew (jconstructor "Hero")))
(java-int-class (jclass "int"))
(get-damage (jmethod hero-class "getDamage" java-int-class))
(use-magic (jmethod hero-class "useMagic" java-int-class))
(method (jmethod hero-class "showStatus")))
(jcall get-damage hero-instance hp)
(jcall use-magic hero-instance mp)
(let (result (jcall method hero-instance))
result)))
Il sera écrit à la manière de Java, mais lorsque vous évaluez réellement cette fonction,
CL-USER> (load "/Path/to/exted-hero.lisp")
T
CL-USER> (extended-hero-status 5 10)
"HP: 95, MP: 90"
Je pense que vous pouvez voir que cela fonctionne correctement.
Qu'as-tu pensé. Avez-vous eu la sensation? Avec ABCL, il peut être possible d'utiliser des bibliothèques Java relativement facilement avec ComonLisp et d'incorporer divers programmes écrits en langage Java dans des projets CL.
Bien que non introduit cette fois, il est bien sûr possible d'appeler Common Lisp depuis le langage Java. Voir la référence utilisateur mentionnée ci-dessus pour plus de détails.
Nous attendons avec impatience vos suggestions et impressions d'erreurs.
[^ Note 1]: J'étais accro à cela parce que je ne comprenais pas l'argument de jnew. [^ Note 2]: Au lieu de passer l'argument lui-même ici, passez l'objet de classe de type de l'argument. Plus précisément, la méthode à distribuer est déterminée en passant quelque chose comme (jclass "int").
Recommended Posts