Préface
Tout le code de cet article est écrit en JavaScript, mais vous pouvez également utiliser d'autres langages de script compatibles JSR 223. Ces exemples peuvent être exécutés sous forme de fichiers de script ou dans des shells interactifs en exécutant une instruction à la fois. La syntaxe pour accéder aux propriétés et aux méthodes des objets en JavaScript est la même que celle de la langue java.
Cet article contient les parties suivantes:
1. Accès aux cours Java
Afin d'accéder aux types natifs ou de référence aux types Java en JavaScript, vous pouvez appeler la fonction Java.type() , qui renvoie le type de l'objet correspondant en fonction du nom de classe complet. Le code suivant montre comment obtenir différents types d'objets:
var arrayList = java.type ("java.util.arraylist"); var intype = java.type ("int"); var stringArrayType = java.type ("java.lang.string []"); var int2darraytype = java.type ("int [] []"); La méthode de retour d'un objet de type utilisant Java.type() dans JavaScript est similaire à celle de Java.
Par exemple, vous pouvez instancier une classe en utilisant la méthode suivante:
var anArrayList = new Java.type ("java.util.arraylist");Les objets de type Java peuvent être utilisés pour instancier des objets Java. Le code suivant montre comment instancier un nouvel objet en utilisant le constructeur par défaut et appeler le constructeur contenant les paramètres:
var arrayList = java.type ("java.util.arraylist"); var defaultsizIzEArrayList = new ArrayList; var douanSizEArrayList = new ArrayList (16); Vous pouvez utiliser Java.type() pour obtenir le type d'objet, et vous pouvez utiliser les méthodes suivantes pour accéder aux propriétés et méthodes statiques:
var file = java.type ("java.io.file"); file.createtempFile ("nashorn", ".tmp"); Si vous souhaitez accéder à la classe statique interne, vous pouvez transmettre le signe du dollar $ à Java.type() .
Le code suivant montre comment renvoyer Float de java.awt.geom.Arc2D :
var float = java.type ("java.awt.geom.arc2d $ float");Si vous avez déjà un objet de type de classe externe, vous pouvez accéder à sa classe intérieure comme vous pourriez accéder à la propriété, comme indiqué ci-dessous:
var arc2d = java.type ("java.awt.geom.arc2d") var float = arc2d.floatPuisqu'il s'agit d'une classe intérieure non statique, l'instance de classe externe doit être transmise sous forme de paramètre au constructeur.
Bien que l'utilisation d'objets de type dans JavaScript soit similaire à celle de Java, il est encore quelque peu différent de l'objet java.lang.Class . Cette différence est la valeur de retour de getClass() . Vous pouvez utiliser class et les propriétés static pour obtenir ces informations.
Le code suivant montre la différence entre les deux:
var arrayList = java.type ("java.util.arraylist"); var a = new ArrayList; // Toutes les suivantes sont vraies: print ("Type agit comme cible d'instance de:" + (une instance Of ArrayList)); (a.getClass ()! == ArrayList)); print ("La propriété` class` 'de Type est la même que GetClass de instance (): "+ (a.getClass () === ArrayList.class)); print (" Type est la mêmeSyntaxe et sémantique, les expressions de classe JavaScript et les objets d'exécution sont similaires à Java Semantics. Cependant, dans Java, l'objet de classe n'a pas de propriété nommée statique car l'expression de classe compilée n'est pas utilisée comme objet.
2. Importer des packages et des cours Java
Afin d'accéder aux classes Java en fonction de son nom simple, nous pouvons utiliser importPackage() et importClass() pour importer des packages et des classes Java. Ces fonctions existent dans le fichier de script de compatibilité (mozilla_compat.js).
L'exemple suivant montre comment utiliser importPackage() et importClass() :
// Chargez la compatibilité scriptload ("nashorn: mozilla_compat.js"); // importe le java.awt packageImportPackage (java.awt); // importe le java.awt.frame classimportclass (java.awt.frame); // crée un nouveau cadre de la catégorie = new java.awt. MethodFrame.SetVisible (true); // accéder à une propriété javabean (frame.title); Les packages Java sont accessibles via la variable globale des packages, tels que Packages.java.util.Vector ou Packages.javax.swing.JFrame . Cependant, le package Java SE standard a des méthodes d'accès plus simples, telles que: Java correspond à packages.java, Javax correspond à packages.javax et org correspond à packages.org.
Le package java.lang ne nécessite pas d'importation par défaut, car cela entrera en conflit avec d'autres objets intégrés JavaScript tels que Object , Boolean et Math . De plus, l'importation de packages et classes Java peut également entraîner des conflits de nom de variable dans le cadre de la portée mondiale de JavaScript. Pour éviter les conflits, nous définissons un objet Javaimporter et limitons la portée des packages et classes Java importés via with , comme indiqué dans le code suivant:
// Créer un objet Javaimpporter avec des packages et des classes spécifiés à l'importvar GUI = New Javaimpporter (java.awt, javax.swing); // transmettez l'objet Javaimpporter à la déclaration "avec" et accédez aux classes // à partir des packages importés par leurs noms simples dans le corps de la déclaration (GUI) {var awtframe = new frame ("awt frame"); var jFrame = new JFrame ("swing jframe");};3. Utilisez des tableaux Java
Afin de créer un objet Java Array, vous devez d'abord obtenir l'objet Java Array Type et l'initialiser. L'attribut de syntaxe et length de l'accès JavaScript aux éléments du tableau est le même que Java, comme indiqué dans le code suivant:
var stringArray = java.type ("java.lang.string []"); var a = new Stringarray (5); // définir la valeur de la première élémenta [0] = "Scripting est super!"; // Imprimez la longueur de l'arrayprint (a.Length); // imprime la valeur de la première élémentPrint (a [0]); Compte tenu d'un tableau JavaScript, nous pouvons également le convertir en un tableau Java en utilisant Java.to() . Nous devons passer le tableau JavaScript en tant que paramètre à la méthode et spécifier le type de tableau à retourner, qui peut être une chaîne ou un objet de type. Nous pouvons également ignorer les paramètres de type objet pour renvoyer le tableau de l'objet []. L'opération de conversion est effectuée selon les règles de conversion ECMAScript. Le code suivant montre comment transformer un tableau JavaScript en un tableau Java via différents paramètres Java.to() :
// Créer un tableau javascript var anArray = [1, "13", false]; // converti un tableau en java int [] array var javaintarray = java.to (anArray, "int []"); print (javaintarray [0]); // imprime le numéro 1Print (javaintArray [1]); // imprime le numéro 13Print (JavaintArray [2]); // imprime le numéro 0 // convertir le tableau JavaScript en javastringArray = java.to (anArray, java.type ("java.lang.string []")); print (javastringArray [0]); // imprime la chaîne "1" imprimer (javastringArray [1]); // imprime la chaîne "13" imprimer (javastringArray [2]); // imprime la chaîne "false" // convertir le tableau JavaScript en objet java [] array var javaObjectArray = java.to (anArray); print (javaObjectArray [0]); // imprime le numéro 1Print (javaObjectArray [1]); // imprime la chaîne "13" print (javaObjectArray [2]); // imprime la valeur booléenne "false" Vous pouvez utiliser Java.from() pour convertir un tableau Java en un tableau JavaScript.
Le code suivant montre comment convertir un tableau contenant la liste des fichiers dans le répertoire actuel en un tableau JavaScript:
// obtient le type de fichier java objectvar file = java.type ("java.io.file"); // créer un tableau java de fichiers objetsvar listcurdir = nouveau fichier ("."). Listfiles (); // converti la baisse Java en javascript; ArrayPrint (JSList);Avis:
Dans la plupart des cas, vous pouvez utiliser des objets Java dans votre script sans les convertir en objets JavaScript.
4. Implémentez l'interface Java
La syntaxe de l'implémentation des interfaces Java dans JavaScript est similaire à la méthode de définition de classes anonymes en Java. Nous avons juste besoin d'instancier l'interface et d'implémenter ses méthodes avec des fonctions JavaScript.
Le code suivant montre comment implémenter l'interface Runnable :
// Créer un objet qui implémente l'interface Runnable en implémentant // la méthode run () en tant que javascript functionvar r = new Java.lang.Runnable () {run: function () {print ("running ... / n"); }}? Si une méthode veut un objet, cet objet implémente une interface avec une seule méthode, vous pouvez transmettre une fonction de script à cette méthode au lieu de passer l'objet. Par exemple, dans l'exemple ci-dessus, Thread() nécessite un objet qui implémente Runnable en tant que paramètre. Nous pouvons profiter de la conversion automatique pour passer une fonction de script au constructeur Thread() .
L'exemple suivant montre comment créer un objet Thread sans implémenter une interface Runnable :
// Définir une fonction de fonction de fonction JavaScript Func () {print ("Je suis func!");}; // Passez la fonction JavaScript au lieu d'un objet qui implémente // le java.lang.runnable interfacevar th = new java.lang.thread (func); th.start (); th.join (); Vous pouvez implémenter plusieurs interfaces en passant des objets de type associés à Java.extend() .
5. étendre les cours de Java abstraits
Vous pouvez instancier une sous-classe de classe abstraite anonyme, il suffit de passer un objet JavaScript au constructeur, qui contient certaines propriétés correspondant aux valeurs implémentées par la méthode de classe abstraite. Si une méthode est surchargée, la fonction JavaScript fournira des implémentations de toutes les variantes de méthode. L'exemple suivant montre comment initialiser une sous-classe de la classe abstraite THIMERTASK:
var timertask = java.type ("java.util.timertask"); var task = new Timertask ({run: function () {print ("Hello world!")}}); En plus d'appeler le constructeur et de passer des paramètres, nous pouvons également fournir des paramètres directement après la new expression.
L'exemple suivant montre comment utiliser cette syntaxe (similaire à la définition des classes internes anonymes en Java), ce qui est un peu plus simple que l'exemple ci-dessus:
var task = new Timertask {run: function () {print ("Hello World!")}};Si la classe abstraite contient une seule méthode abstraite (type SAM), nous n'avons pas besoin de passer un objet JavaScript au constructeur, nous pouvons passer une interface de fonction qui implémente la méthode. L'exemple suivant montre comment utiliser les types SAM pour simplifier le code:
var task = new Timertask (function () {print ("Hello World!")});Quelle que soit la syntaxe que vous choisissez, si vous avez besoin d'appeler un constructeur contenant des paramètres, vous pouvez spécifier des paramètres dans l'objet et la fonction d'implémentation.
Si vous souhaitez appeler une méthode Java qui nécessite des paramètres de type SAM, vous pouvez transmettre une fonction JavaScript à la méthode. Nashorn instanciera une sous-classe en fonction des besoins de la méthode et utilisera cette fonction pour implémenter la méthode abstraite unique.
Le code suivant montre comment appeler Timer.schedule() , qui nécessite un objet Tirmertask en tant que paramètre:
var timer = java.type ("java.util.timer"); timer.schedule (function () {print ("Hello world!")});Avis:
La syntaxe précédente suppose que le type SAM requis est une interface ou contient un constructeur par défaut, que Nashorn utilise pour initialiser une sous-classe. Ce n'est pas possible d'utiliser une classe qui ne contient pas le constructeur par défaut.
6. étendre des cours Java spécifiques
Pour éviter la confusion, la syntaxe pour étendre les classes abstraites ne peut pas être utilisée pour étendre les classes de béton. Parce qu'une classe concrète peut être instanciée, une telle syntaxe est analysée dans une tentative de créer une nouvelle instance de classe et de passer l'objet de la classe requise par le constructeur (si le type d'objet attendu est une interface). Pour démontrer ce problème, veuillez jeter un œil à l'exemple de code suivant:
var t = new java.lang.thread ({run: function () {print ("Thread Running!")}}); Cette ligne de code est analysée pour étendre la classe Thread et implémenter run() , et l'instanciation de Thread est transmise à son constructeur un objet qui implémente l'interface Runnable.
Pour étendre une classe de béton, transmettez son objet de type à la fonction Java.extend() , puis renvoyez son objet de type à sa sous-classe. Ensuite, vous pouvez utiliser l'objet type de cette sous-classe pour créer des instances et fournir des implémentations de méthode supplémentaires.
Le code suivant vous montrera comment prolonger Thread et implémenter run() :
var thread = java.type ("java.lang.thread"); var threadExtender = java.Extend (thread); var t = new ThreadExtender () {run: function () {print ("thread running!")}}; Java.extend() peut obtenir une liste de plusieurs types d'objets. Vous ne pouvez pas spécifier plus d'un objet de type Java, ou vous pouvez spécifier le nombre d'objets de type autant que les interfaces Java. L'objet de type renvoyé étend la classe spécifiée (ou java.lang.Object , s'il n'y a pas d'objet de type spécifié), cette classe implémente toutes les interfaces. Les objets types de la classe n'ont pas besoin d'être en haut de la liste.
7. Méthodes pour accéder à la superclasse (classe parent)
Les méthodes qui souhaitent accéder à la classe parent peuvent utiliser la fonction Java .super() .
L'exemple suivant montre comment étendre java.lang.Exception et accéder aux méthodes de la classe parent.
Exemple 3-1 Méthode pour accéder à la classe parent (super.js) var exception = java.type ("java.lang.exception"); var exceptionAdapter = java.Extend (exception); var exception = new exceptionAdapter ("mon message exception") {getMessage: function () {var _super_ = java.super (exception); return _Super_.getMessage (). ToupperCase (); }} essayez {lancer une exception;} catch (ex) {print (exception);}Si vous exécutez le code ci-dessus, vous imprimerez ce qui suit:
jdk.nashorn.javaadapters.java.lang.exception: mon message d'exception
8. Liaison à la mise en œuvre
Dans la section précédente, nous avons décrit comment étendre les classes Java et implémenter l'interface à l'aide d'un paramètre d'objet JavaScript supplémentaire. L'implémentation est liée sur une instance spécifique, qui est créée via de nouvelles, pas de la classe entière. Il y a certains avantages à procéder, comme l'empreinte mémoire à l'exécution, car Nashorn peut créer un seul adaptateur universel pour la combinaison de types de chaque implémentation.
L'exemple suivant montre que différentes instances peuvent être la même classe Java, mais leurs objets d'implémentation JavaScript sont différents:
var runnable = java.lang.runnable; var r1 = new runnable (function () {print ("I'm runnable 1!")}); var r2 = new runnable (function () {print ("I'm runnable 2!")}); r1.run (); r2.run (); imprimer ("nous partageons la même classe:" + (r1.clc == R2.Le code ci-dessus imprimera le résultat suivant:
Je suis en cours d'exécution 1! Je suis en cours d'exécution 2! Nous partageons la même classe: vrai
Si vous souhaitez transmettre une instance d'une classe à une API externe (comme le framework Javafx, passer une instance d'application à l'API Javafx), vous devez prolonger une classe Java ou implémenter une interface liée à cette classe, plutôt que son instance. Vous pouvez implémenter la classe en passant une liaison d'objets JavaScript et en la transmet au dernier paramètre de la fonction java.extend (). Cela crée une nouvelle classe avec le même constructeur que la classe d'origine, car ils ne nécessitent pas d'implémentation supplémentaire des paramètres d'objet.
L'exemple suivant montre comment lier une implémentation dans une classe et démontre que les classes d'implémentation sont différentes pour différents appels dans ce cas:
var runnableIMPL1 = Java.Extend (java.lang.runnable, function () {print ("I'm Runnable 1!")}); var runnableImpl2 = java.Extend (java.lang.runnable, function () {print ("I'm runnable 2!")}); var r1 = new RunnableImpl1 (); RunnableImpl2 (); r1.run (); r2.run (); print ("nous partageons la même classe:" + (r1.class === r2.class));L'exemple de résultats d'exécution ci-dessus est le suivant:
Je suis en cours d'exécution 1! Je suis en cours d'exécution 2! Nous partageons la même classe: False
Le déplacement de l'objet d'implémentation de l'appel constructeur vers Java.extend() évite les paramètres supplémentaires requis dans l'appel du constructeur. Chaque appel à Java.extend() nécessite un objet d'implémentation de la classe spécifiée pour générer une nouvelle classe d'adaptateur Java. Les classes d'adaptateur implémentées avec les limites de classe peuvent toujours utiliser un paramètre de constructeur supplémentaire pour remplacer davantage le comportement d'une instance spécifique. Vous pouvez donc fusionner ces deux méthodes: vous pouvez fournir une partie de l'implémentation JavaScript dans une classe de base, puis la transmettre à la fonction Java.extend() , et fournir une implémentation d'instance dans l'objet et la transmettre au constructeur. Certaines définitions de fonction de l'objet seront écrasées lorsque l'objet est défini et transmis au constructeur.
Le code suivant montre comment écraser une fonction d'un objet limite de classe en passant une fonction au constructeur:
var runnableImpl = java.extend (java.lang.runnable, function () {print ("je suis runnable 1!")}); var r1 = new runnableIMPl (); var r2 = new RunnableImpl (function () {print ("je suis runnable 2!")}); r1.run (); (r1.class === r2.class));Les résultats d'impression après l'exemple ci-dessus sont exécutés sont les suivants:
Je suis en cours d'exécution 1! Je suis en cours d'exécution 2! Nous partageons la même classe: vrai
9. Sélectionner la variante de surcharge de la méthode
Les méthodes Java peuvent être surchargées en utilisant différents types de paramètres. Le compilateur Java (Javac) sélectionnera la méthode correcte à exécuter au moment de la compilation. L'analyse des méthodes surchargées Java à Nashorn est exécutée lorsque la méthode est appelée. C'est également un moyen de déterminer la méthode correcte en fonction du type de paramètre. Mais si le type de paramètre réel provoque l'ambiguïté, nous pouvons explicitement spécifier une variante surchargée spécifique. Cela améliore les performances de l'exécution du programme, car le moteur Nashorn n'a pas besoin de distinguer la méthode à appeler pendant l'appel.
Les variantes surchargées sont exposées comme propriétés spéciales. Nous pouvons nous référer à eux sous la forme de chaînes, qui contiennent des noms de méthode et des types de paramètres, et sont entourés de parenthèses.
L'exemple suivant montre comment appeler System.out.println() avec Object , nous lui transmettons une chaîne "Hello":
var out = java.lang.system.out; out ["println (objet)"] ("Bonjour");Dans l'exemple ci-dessus, l'utilisation du nom de classe d'objet est suffisante car c'est la signature qui identifie de manière unique la bonne. Le cas où vous devez utiliser le nom complet de la classe est que deux fonctions variantes surchargées utilisent différents types de paramètres, mais le type a le même nom (cela est possible, par exemple, différents packages contiennent le même nom de classe).
10. Types de données de cartographie
La grande majorité des conversions précédentes Java et JavaScript fonctionnent bien comme vous vous en doutez. Dans les chapitres précédents, nous avons mentionné quelques mappages de types de données simples entre Java et JavaScript. Par exemple, les données de type de tableau peuvent être explicitement converties, les fonctions JavaScript peuvent être automatiquement converties en types SAM lorsqu'elles sont passées sous forme de paramètres en méthodes Java. Chaque objet JavaScript implémente l'interface java.util.Map pour permettre à l'API d'accepter directement les mappages. Lorsqu'ils passent des valeurs à l'API Java, ils seront convertis en type numérique cible attendu, qui peut être un type d'encapsulation ou un type de données primitif. Si le type de cible n'est pas très certain (comme le nombre), vous pouvez seulement l'exiger qu'il s'agit du type de nombre, puis encapsuler spécifiquement le type, tel que le double, entier, long, etc. L'optimisation interne fait la valeur numérique de tout type de package. Collègues, vous pouvez transmettre n'importe quelle valeur JavaScript à l'API Java, qu'il s'agisse d'un type encapsulé ou d'un type primitif, car l'algorithme de conversion ToNumber de JavaScript traitera automatiquement sa valeur. Si une méthode Java nécessite un paramètre String ou d'objet Boolean , JavaScript utilisera les transformations ToString et ToBoolean pour obtenir sa valeur.
Avis:
En raison des considérations d'optimisation des performances internes pour les opérations de chaîne, les chaînes JavaScript ne correspondent pas toujours au type java.lang.string, ou ils peuvent également être java.lang.CharSequence . Si vous transmettez une chaîne JavaScript à une méthode Java qui nécessite le paramètre java.lang.String , alors la chaîne JavaScript est le type java.lang.String , mais si la signature de votre méthode veut être plus générique (par exemple, le type de paramètre accepté est CharSequence ), alors l'objet paramètre que vous réalisez.
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que cela sera d'une aide à l'étude et au travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer.