Предисловие
Весь код в этой статье написан в JavaScript, но вы также можете использовать другие языки сценариев, совместимые с JSR 223. Эти примеры можно запускать в виде файлов сценариев или в интерактивных оболочках, запустив один оператор за раз. Синтаксис для доступа к свойствам и методам объектов в JavaScript такой же, как у языка Java.
Эта статья содержит следующие части:
1. Доступ к классам Java
Чтобы получить доступ к нативным типам или ссылка на типы Java в JavaScript, вы можете вызвать функцию Java.type() , которая возвращает тип соответствующего объекта на основе передачи в полном имени класса. Следующий код показывает, как получить разные типы объектов:
var arraylist = java.type ("java.util.arraylist"); var inttype = java.type ("int"); var stringarraytype = java.type ("java.lang.string []"); var int2darraytype = java.type ("int []"); Метод возврата объекта типа с использованием функции Java.type() в JavaScript аналогичен на Java.
Например, вы можете создать экземпляр класса, используя следующий метод:
var anarraylist = new java.type ("java.util.arraylist");Объекты типа Java могут использоваться для создания объектов Java. Следующий код показывает, как создать создание нового объекта, используя конструктор по умолчанию и вызовите конструктор, содержащий параметры:
var arraylist = java.type ("java.util.arraylist"); var defaultizearraylist = new Arraylist; var customsizearraylist = new ArrayList (16); Вы можете использовать метод Java.type() для получения типа объекта, и вы можете использовать следующие методы для доступа к статическим свойствам и методам:
var file = java.type ("java.io.file"); file.createtempfile ("nashorn", ".tmp"); Если вы хотите получить доступ к внутреннему статическому классу, вы можете передать знак доллара $ методу Java.type() .
Следующий код показывает, как вернуть Float -внутренний класс java.awt.geom.Arc2D :
var float = java.type ("java.awt.geom.arc2d $ float");Если у вас уже есть внешний объект типа класса, то вы можете получить доступ к его внутреннему классу так же, как вы бы получили доступ к свойству, как показано ниже:
var arc2d = java.type ("java.awt.geom.arc2d") var float = arc2d.floatПоскольку это нестатический внутренний класс, экземпляр внешнего класса должен передаваться в качестве параметра конструктору.
Хотя использование объектов типа в JavaScript аналогично тем, что в Java все еще несколько отличается от объекта java.lang.Class . Эта разница заключается в возвратном значении метода getClass() . Вы можете использовать class и static свойства, чтобы получить эту информацию.
Следующий код показывает разницу между двумя:
var arraylist = java.type ("java.util.arraylist"); var a = new ArrayList; // Все следующие: true: print ("Тип действует как цель экземпляра:" + (экземпляр ArrayList)); print ("класс не действует как цель экземпляра:" +! (a.getClass ()! == ArrayList)); Print ("Type` свойство класса 'такое же, что и getClass (): " + (a.getClass () === Arraylist.class)); Print (" Тип такой же, как и array -lepress of getClass (): " + (A.getClass ().Синтаксис и семантика, экспрессии класса JavaScript и объекты времени выполнения аналогичны семантике Java. Однако в Java объект класса не имеет свойства с именем статическим, поскольку скомпилированное выражение класса не используется в качестве объекта.
2. Импорт пакетов и классов Java
Чтобы получить доступ к классам Java на основе его простого имени, мы можем использовать функции importPackage() и importClass() для импорта пакетов и классов Java. Эти функции существуют в файле скрипта совместимости (mozilla_compat.js).
В следующем примере показано, как использовать функции importPackage() и importClass() :
// Scriptload Compatibility ("Nashorn: mozilla_compat.js"); // Импорт java.awt PackageImptorPackage (java.awt); // Импорт java.awt.frame classimportclass (java.awt.frame); // Создать новый каркас объект. setVisible () methodFrame.setVisible (true); // Доступ к Javabean Propertyprint (frame.title); Доступ к Java можно получить через глобальную переменную пакеты, такие как Packages.java.util.Vector или Packages.javax.swing.JFrame . Тем не менее, стандартный пакет Java SE имеет более простые методы доступа, такие как: Java соответствует Packages.java, Javax соответствует Packages.javax и Org соответствует packages.org.
Пакет Java.Lang не требует импорта по умолчанию, потому что это будет противоречить другими встроенными объектами JavaScript, такими как Object , Boolean и Math . Кроме того, импорт любых пакетов Java и классов также может вызвать конфликты имени переменной под глобальным объемом JavaScript. Чтобы избежать конфликтов, мы определяем объект Javaimporter и ограничиваем объем импортированных пакетов и классов Java через with , как показано в следующем коде:
// Создать объект Javaimporter с указанными пакетами и классами для ImportVar gui = new Javaimporter (java.awt, javax.swing); // передавать объект javaimporter в «С» утверждение и доступ к классам // из импортированных пакетов по их простым именам в теле утверждения (gui) {var awtframe = wat awt frame »; var jframe = new jframe ("swing jframe");};3. Используйте массивы Java
Чтобы создать объект массива Java, вам сначала необходимо получить объект типа массива Java и инициализировать его. Атрибут синтаксиса и length JavaScript Access к элементам массива такая же, как Java, как показано в следующем коде:
var stringArray = java.type ("java.lang.string []"); var a = new stringarray (5); // Установить значение первого элемента [0] = "Сценарий великолепен!"; // Печать длины ArrayPrint (A.Length); // печатать значение первого elementPrint (a [0]); Учитывая массив JavaScript, мы также можем преобразовать его в массив Java, используя метод Java.to() . Нам нужно передать массив JavaScript в качестве параметра методу и указать тип возвращаемого массива, который может быть строкой или объектом типа. Мы также можем игнорировать параметры объекта типа, чтобы вернуть массив объекта []. Операция конверсии выполняется в соответствии с правилами конверсии ECMASCRICT. Следующий код показывает, как превратить массив JavaScript в массив Java через разные параметры Java.to() :
// Создать массив JavaScript var anarray = [1, "13", false]; // преобразовать массив в java int [] массив var javaintarray = java.to (anarray, "int []"); print (javaintarray [0]); // печатает номер 1PRINT (javaintarray [1]); // печатает номер 13print (javaintarray [2]); // печатает номер 0 // Конвертируйте массив JavaScript в javastringarray = java.to (anarray, java.type ("java.lang.string []")); print (javastringarray [0]); // печатает строку «1» печати (javastringarray [1]); // печатает строку «13» печати (javastringarray [2]); // печатает строку «false» // преобразование массива JavaScript в Java Object [] Array var javaObjectArray = java.to (anarray); print (javaobjectarray [0]); // печатает номер 1 -ти (javaobjectarray [1]); // печатает строку «13» печати (javaobjectarray [2]); // печатает логическое значение "false" Вы можете использовать метод Java.from() для преобразования массива Java в массив JavaScript.
Следующий код показывает, как преобразовать массив, содержащий список файлов в текущем каталоге в массив JavaScript:
// Получить Java -файл типа objectVar file = java.type ("java.io.file"); // Создать массив Java file objectsvar listcurdir = new File ("."). Arrayprint (JSList);Уведомление:
В большинстве случаев вы можете использовать Java -объекты в своем сценарии, не преобразуя их в объекты JavaScript.
4. Реализация интерфейса Java
Синтаксис реализации интерфейсов Java в JavaScript аналогичен методу определения анонимных классов в Java. Нам просто нужно создать экземпляр интерфейса и реализовать его методы с помощью функций JavaScript.
Следующий код демонстрирует, как реализовать Runnable интерфейс:
// Создать объект, который реализует runnable interface, реализуя // метод run () как javascript functionvar r = new java.lang.runnable () {run: function () {print ("running .../n"); }}; // переменная R может быть передана методам Java, которые ожидают реализации объекта // java.lang.runnable interfacevar th = new java.lang.thread (r); th.start (); th.join (); Если метод хочет объект, этот объект реализует интерфейс только с одним методом, вы можете передать функцию скрипта этому методу вместо передачи объекта. Например, в приведенном выше примере конструктор Thread() требует объекта, который реализует Runnable интерфейс в качестве параметра. Мы можем воспользоваться автоматическим преобразованием, чтобы передать функцию сценария в конструктор Thread() .
В следующем примере показано, как создать объект Thread без реализации Runnable интерфейса:
// Определить функцию функции функции JavaScript func () {print ("I Am Func!");}; // пройти функцию JavaScript вместо объекта, который реализует // java.lang.runnable interfacevar th = new java.lang.thread (func); th.start (); Вы можете реализовать несколько интерфейсов, передавая функцию связанных типов в функцию Java.extend() .
5. Расширить абстрактные классы Java
Вы можете создать экземпляр анонимного абстрактного подкласса класса, просто передайте объект Javascript к конструктору, который содержит некоторые свойства, соответствующие значениям, реализованным методом абстрактного класса. Если метод перегружен, функция JavaScript предоставит реализации всех вариантов метода. В следующем примере показано, как инициализировать подкласс абстрактного класса Timertask:
var timertask = java.type ("java.util.timertask"); var task = new timertask ({run: function () {print ("hello world!")}}); В дополнение к вызову конструктора и прохождения параметров, мы также можем предоставить параметры непосредственно после new выражения.
В следующем примере показано, как использовать этот синтаксис (аналогично определению анонимных внутренних классов в Java), что немного проще, чем приведенный выше пример:
var task = new Timertask {run: function () {print ("hello world!")}};Если абстрактный класс содержит один абстрактный метод (тип SAM), то нам не нужно передавать объект JavaScript в конструктор, мы можем передать интерфейс функции, который реализует метод. В следующем примере показано, как использовать типы SAM для упрощения кода:
var task = new TimerTask (function () {print ("Hello World!")});Независимо от выбранного вами синтаксиса, если вам нужно вызвать конструктор, который содержит параметры, вы можете указать параметры в объекте и функции реализации.
Если вы хотите вызвать метод Java, который требует параметров типа SAM, вы можете передать функцию JavaScript в метод. Nashorn создаст экземпляр подкласса в соответствии с потребностями метода и использует эту функцию для реализации уникального абстрактного метода.
Следующий код показывает, как вызвать метод Timer.schedule() , который требует объекта Timertask в качестве параметра:
var -timer = java.type ("java.util.timer"); timer.schedule (function () {print ("hello world!")});Уведомление:
Предыдущий синтаксис предполагает, что требуемый тип SAM является интерфейсом или содержит конструктор по умолчанию, который Nashorn использует для инициализации подкласса. Это невозможно использовать класс, который не содержит конструктор по умолчанию.
6. расширить конкретные классы Java
Чтобы избежать путаницы, синтаксис для расширения абстрактных классов не может быть использован для расширения конкретных классов. Поскольку конкретный класс может быть создан, такой синтаксис анализируется в попытке создать новый экземпляр класса и пройти объект класса, требуемый конструктором (если ожидаемый тип объекта является интерфейсом). Чтобы продемонстрировать эту проблему, посмотрите на следующий пример кода:
var t = new java.lang.thread ({run: function () {print ("trade running!")}}); Эта строка кода проанализирована для расширения класса Thread и реализации метода run() , а экземпляр класса Thread передается своему конструктору объекту, который реализует запускаемый интерфейс.
Чтобы расширить конкретный класс, передайте его объект типа в функцию Java.extend() , а затем верните свой объект типа в подкласс. Затем вы можете использовать объект типа этого подкласса для создания экземпляров и предоставления дополнительных реализаций метода.
Следующий код покажет вам, как расширить класс Thread и реализовать метод run() :
var think = java.type ("java.lang.thread"); var threadextender = java.extend (thread); var t = new ThreadExtender () {run: function () {print ("running!")}}; Функция Java.extend() может получить список нескольких типов объектов. Вы можете указать не более одного объекта типа Java, или вы можете указать количество объектов типа столько, сколько интерфейсы Java. Возвращенный объект типа расширяет указанный класс (или java.lang.Object , если нет указанного объекта типа), этот класс реализует все интерфейсы. Типовые объекты класса не должны быть в верхней части списка.
7. Методы доступа к SuperClass (родительский класс)
Методы, которые хотят получить доступ к родительскому классу, могут использовать функцию Java .super() .
В следующем примере показано, как расширить класс java.lang.Exception и получить доступ к методам родительского класса.
Пример 3-1 Метод для доступа к родительскому классу (super.js) var exception = java.type ("java.lang.exception"); var exceptionAdapter = java.extend (exception); var exception = new ExceptionAdapter ("my exception message") {getMessage: function () {var _super_ = java.super (execurity); return _super_.getmessage (). Touppercase (); }} try {throw Exception;} catch (ex) {print (Exception);}Если вы запустите приведенный выше код, вы напечатаете следующее:
jdk.nashorn.javaadapters.java.lang.exception: мое исключение сообщение
8. Связывание для реализации к классу
В предыдущем разделе мы описали, как расширить классы Java и реализовать интерфейс, используя дополнительный параметр объекта JavaScript. Реализация связана с конкретным экземпляром, который создается через новый, а не весь класс. Есть некоторые преимущества для этого, такие как следы памяти во время выполнения, поскольку Нашорн может создать один универсальный адаптер для комбинации типов каждой реализации.
В следующем примере показано, что разные экземпляры могут быть одним и тем же классом Java, но их объекты реализации JavaScript разные:
var runnable = java.lang.runnable; var r1 = new Runnable (function () {print ("I'm Runnable 1!")}); var r2 = new Runnable (function () {print ("It Runnable 2!")}); R1.Run (); r2.run ();Приведенный выше код будет распечатать следующий результат:
Я запускаю 1! Я бегу 2! Мы делимся одним и тем же классом: правда
Если вы хотите перенести экземпляр класса на внешний API (например, Framework Javafx, передавая экземпляр приложения в API Javafx), вы должны расширить класс Java или реализовать интерфейс, связанный с этим классом, а не его экземпляр. Вы можете реализовать класс, передавая привязку объекта JavaScript и передавая его к последнему параметру функции java.extend (). Это создает новый класс с тем же конструктором, что и исходный класс, потому что они не требуют дополнительной реализации параметров объекта.
В следующем примере показано, как связать реализацию в класс и демонстрировать, что классы реализации различны для разных вызовов в этом случае:
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!")}); RunnableImpl2 (); r1.run (); r2.run (); print («Мы разделяем тот же класс:» + (r1.class === r2.class));Результаты выполнения приведенного выше следующего:
Я запускаю 1! Я бегаю 2! Мы делимся одним и тем же классом: ложь
Перемещение объекта реализации из вызова конструктора в вызов функции Java.extend() позволяет избежать дополнительных параметров, необходимых в вызове конструктора. Каждый вызов функции Java.extend() требует объекта реализации указанного класса для создания нового класса адаптера Java. Классы адаптера, реализованные с границами классов, все еще могут использовать дополнительный параметр конструктора для дальнейшего переопределения поведения конкретного экземпляра. Таким образом, вы можете объединить эти два метода: вы можете предоставить часть реализации JavaScript в базовом классе, затем передать его функции Java.extend() , и предоставить реализацию экземпляра в объекте и передать его конструктору. Некоторые определения функций объекта будут перезаписаны, когда объект определяется и передается конструктору.
Следующий код демонстрирует, как перезаписать функцию объекта границы класса, передавая функцию конструктору:
var runnableImpl = java.extend (java.lang.runnable, function () {print ("I'm Runnable 1!")}); var r1 = new RunnableImpl (); var r2 = new RunnableImpl (function () {print (я runnable 2! ")}); r1.run (); (r1.class === r2.class));Результаты печати после выполнения приведенного выше примера следующие:
Я запускаю 1! Я бегу 2! Мы делимся одним и тем же классом: правда
9. Выберите вариант перегрузки метода
Методы Java могут быть перегружены с помощью различных типов параметров. Компилятор Java (Javac) выберет правильный метод для выполнения во время компиляции. Проанализирование перегруженных методов Java в Нашорне выполняется при вызове метода. Это также способ определить правильный метод, основанный на типе параметра. Но если фактический тип параметра вызовет двусмысленность, мы можем явно указать конкретный перегруженный вариант. Это улучшает производительность выполнения программы, потому что двигатель Nashorn не должен различать, какой метод вызовется во время вызова.
Перегруженные варианты выставлены как специальные свойства. Мы можем ссылаться на них в форме строк, которые содержат имена методов и типы параметров, и окружены скобками.
В следующем примере показано, как вызвать метод System.out.println() с вариантом параметра Object , мы передаем строку «Привет»:
var out = java.lang.system.out; out ["println (Object)"] ("hello");В приведенном выше примере достаточно использования имени класса объекта достаточно, потому что это подпись однозначно идентифицирует правильную. Случай, когда вы должны использовать полное имя класса, заключается в том, что две перегруженные функции варианта используют разные типы параметров, но тип имеет одинаковое имя (например, это возможно, разные пакеты содержат одно и то же имя класса).
10. Картирование типов данных
Подавляющее большинство предыдущих преобразований Java и JavaScript работают хорошо, как и следовало ожидать. В предыдущих главах мы упомянули некоторые простые сопоставления типа данных между Java и JavaScript. Например, данные типа массива могут быть явно преобразованы, функции JavaScript могут быть автоматически преобразованы в типы SAM при передаче в качестве параметров в методы Java. Каждый объект JavaScript реализует интерфейс java.util.Map , чтобы позволить API непосредственно принимать отображения. При передаче значений в Java API они будут преобразованы в ожидаемый целевой числовой тип, который может быть типом инкапсуляции или примитивным типом данных. Если целевой тип не очень определен (например, число), вы можете потребовать только типа числа, а затем специфически инкапсулировать тип, такой как двойное, целое число, длинное и т. Д. Внутренняя оптимизация делает числовое значение любого типа пакета. Коллеги, вы можете передать любое значение JavaScript в Java API, будь то инкапсулированный тип или примитивный тип, поскольку алгоритм преобразования ToNumber JavaScript автоматически обрабатывает свое значение. Если метод Java требует параметра String или Boolean объекта, JavaScript будет использовать ToString и ToBoolean Transformations для получения его значения.
Уведомление:
Из -за внутренних соображений оптимизации производительности для строковых операций строки JavaScript не всегда соответствуют типу java.lang.string, или они также могут быть типом java.lang.CharSequence . Если вы передаете строку JavaScript методу Java, который требует параметра java.lang.String , то строка JavaScript является типом java.lang.String , но если ваша подпись метода хочет быть более общим (например, принятый тип параметра - это Java.Lang.Object), то объект CharSequence , который вы получаете, будет создавать объект.
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что это поможет всем, кто учится и работа. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения.