Objective
All the code in this article is written in JavaScript, but you can also use a scripting language that is compatible with JSR 223. These examples can be used as script files or as a way to run a single statement in an interactive Shell. The syntax for accessing objects ' properties and methods in JavaScript is the same as in the Java language.
This article contains the following sections:
1. Visit Java class
To access native types in JavaScript or to reference Java types, you can call a Java.type()
function that returns the type of the corresponding object based on the full class name passed in. The following code shows how to get different object types:
var ArrayList = Java.type ("Java.util.ArrayList");
var inttype = java.type ("int");
var stringarraytype = Java.type ("java.lang.string[]");
var int2darraytype = Java.type ("int[][]");
The method of using a Java.type()
type object returned by a function in JavaScript is similar to that in Java.
For example, you can instantiate a class by using the following methods:
var anarraylist = new Java.type ("Java.util.ArrayList");
Java-type objects can be used to instantiate Java objects. The following code shows how to instantiate a new object using the default constructor and invoke the constructor that contains the parameter:
var ArrayList = Java.type ("Java.util.ArrayList");
var defaultsizearraylist = new ArrayList;
var customsizearraylist = new ArrayList (16);
You can use Java.type()
methods to get object types, and you can use the following methods to access static properties and methods:
var File = Java.type ("Java.io.File");
File.createtempfile ("Nashorn", ". tmp");
If you want to access the internal static class, you can pass the dollar sign $ to Java.type()
method.
The following code shows how to return java.awt.geom.Arc2D
the Float
inner class:
var Float = Java.type ("Java.awt.geom.arc2d$float");
If you already have an external class type object, you can access its inner class like an Access property, as follows:
var arc2d = Java.type ("Java.awt.geom.Arc2D")
var Float = arc2d.float
Because a non-static inner class, an external class instance must be passed as a parameter to the constructor.
Although the use of type objects in JavaScript is similar to that in Java, they java.lang.Class
are somewhat different from objects, the difference being the getClass()
return value of the method. You can use class
and static
attribute to get this information.
The following code shows the difference between the two:
var ArrayList = Java.type ("Java.util.ArrayList");
var a = new ArrayList;
All of the following are true:
print ("Type acts as target of instanceof:" + (a instanceof ArrayList));
Print ("Class doesn ' t act as target of instanceof:" +!) ( A instanceof A.getclass ());
Print (' Type is not ' the same as instance ' s GetClass (): ' + (A.getclass ()!== ArrayList));
Print ("Type ' s ' class ' property is the same as instance ' s GetClass ():" + (a.getclass () = = Arraylist.class));
Print ("Type is" the same as the ' static ' instance ' s GetClass (): "+ (A.getclass (). static = = ArrayList));
In syntax and semantics, JavaScript is similar to Java semantics in compile-time class expressions and Run-time objects. In Java, however, the class object is not a property named Static, because the class expression at compile time is not an object.
2. Import Java Packages and classes
To access Java classes based on their simple names, we can use importPackage()
and importClass()
function to import Java packages and classes. These functions exist in the compatibility script file (mozilla_compat.js).
The following example shows how to use importPackage()
and importClass()
function:
Load compatibility script
load ("Nashorn:mozilla_compat.js");
Import the java.awt package
importpackage (java.awt);
Import the Java.awt.Frame class
Importclass (Java.awt.Frame);
Create a new Frame object
var frame = new Java.awt.Frame ("Hello");
Call the SetVisible () method
frame.setvisible (true);
Access a JavaBean property
print (Frame.title);
You can access Java packages by Packages Global variables, such as Packages.java.util.Vector
or Packages.javax.swing.JFrame
. However, standard Java SE packages have simpler access methods, such as Java counterpart Packages.java, Javax correspondence Packages.javax, and org corresponding packages.org.
The Java.lang package does not need to be imported by default because it conflicts with, and so on, Object
other objects that are Boolean
built in Math
JavaScript. In addition, importing any Java packages and classes can also cause variable name conflicts under JavaScript global scope. To avoid conflicts, we define a Javaimporter object and use with
statements to limit the scope of the imported Java packages and classes, as shown in the following code:
Create a Javaimporter object with specified packages and classes to import
var Gui = new Javaimporter (java.awt, JAV ax.swing);
Pass the Javaimporter object to the ' with ' statement and access the classes
//from the imported packages by their Simple names within the statement ' s body with
(Gui) {
var awtframe = new Frame ("AWT frame");
var jframe = new JFrame ("Swing jframe");
3. Using Java arrays
To create a Java array object, you first need to get the Java array type object and initialize it. JavaScript accesses array elements in syntax and length
properties like Java, as shown in the following code:
var Stringarray = Java.type ("java.lang.string[]");
var a = new Stringarray (5);
Set the value of
the ' the ' the ' the ' the ' the ' the ' ' scripting is great! ' = ' a[0 '
Print the length of the array
print (a.length);
Print the value of the the ' the ' the ' the ' the ' the ' of the ' the '
;
Given a JavaScript array, we can also use Java.to()
the method to turn it into a Java array. We need to pass the JavaScript array as a parameter to the method and specify the type of array to return, either a string or a type object. We can also ignore the type object arguments to return the object[] array. The conversion operation is based on the ECMAScript conversion rule. The following code shows how to Java.to()
turn a JavaScript array into a Java array with different parameters:
Create a JavaScript array
var anarray = [1, ", false];
" Converts an array to a Java int[] array
var javaintarray = java.to (Anarray, "int[]");
Print (javaintarray[0]); Prints the number 1
print (javaintarray[1]);//Prints the number
print (javaintarray[2);//Prints the Numbe R 0
//convert JavaScript array to Java string[] array
var javastringarray = java.to (Anarray, Java.type ("java.lang.string[") ));
Print (javastringarray[0]); Prints the string "1"
print (javastringarray[1]);//Prints the string "print"
(javastringarray[2);//PRI NTS the string "false"
///convert JavaScript array to Java object[] array
var javaobjectarray = java.to (Anarray);
Print (javaobjectarray[0]); Prints the number 1
print (javaobjectarray[1]);//Prints the string "print"
(javaobjectarray[2);//Print S the boolean value "false"
You can use Java.from()
the method to turn a Java array into a JavaScript array.
The following code shows how to convert an array containing the list of files in the current directory into a JavaScript array:
Get the Java file type Object
var file = Java.type ("Java.io.File");
Create a Java array of File objects
var listcurdir = new File ("."). Listfiles ();
Convert the Java array to a JavaScript array
var jslist = Java.from (listcurdir);
Print the JavaScript array
print (jslist);
Attention:
In most cases, you can use Java objects in your scripts without converting them into JavaScript objects.
4. Implement Java interface
The syntax for implementing Java interfaces in JavaScript is similar to the method of defining anonymous classes in Java. We just need to instantiate the interface and implement its methods using JavaScript functions.
The following code shows how to implement an Runnable
interface:
Create an object so implements the Runnable interface by implementing
//The Run () method as a JavaScript functio n
var r = new Java.lang.Runnable () {
run:function () {
print ("running...\n");
}
;
The R variable can is passed to Java methods, expect an object implementing
//The Java.lang.Runnable interface
var th = new Java.lang.Thread (r);
Th.start ();
Th.join ();
If a method wants an object that implements an interface with only one method, you can pass a script function to this method instead of passing the object. For example, in the example above, the Thread()
constructor requires an Runnable
object that implements the interface as an argument. We can use the advantages of automatic conversion to pass a script function to the Thread()
constructor.
The following example shows how to create an Thread
object without implementing an Runnable
interface:
Define a JavaScript function
function func () {
print ("I am func!");
Pass the JavaScript function instead of the implements
//The Java.lang.Runnable interface
var th = New Java.lang.Thread (func);
Th.start ();
Th.join ();
You can implement multiple interfaces by passing related types of objects to Java.extend()
functions.
5. Extend abstract Java class
You can instantiate a subclass of an anonymous abstract class and just pass a JavaScript object to the constructor that contains some attributes that correspond to the values of the abstract class method implementation. If a method is overloaded, the JavaScript function will provide implementations of all method variants. The following example shows how to initialize a subclass of an abstract class TimerTask:
var timertask = Java.type ("Java.util.TimerTask");
The var task = new TimerTask ({run:function () {print ("Hello world!")}});
In addition to calling constructors and passing arguments, we can also new
provide arguments directly after an expression.
The following example shows how the syntax is used (similar to the definition of the Java anonymous inner Class), which is simpler than the example above:
var task = new TimerTask {
run:function () {
print ("Hello world!")
}}
;
If the abstract class contains a single abstract method (SAM type), then we do not have to pass the JavaScript object to the constructor, and we can pass a function interface that implements the method. The following example shows how to use the SAM type to simplify the code:
The var task = new TimerTask (function () {print ("Hello world!")});
Whichever syntax you choose, if you need to call a constructor that contains parameters, you can specify parameters in the implementation object and function.
If you want to invoke a Java method that requires a SAM type parameter, you can pass a JavaScript function to the method. Nashorn will instantiate a subclass based on the method needs and use this function to implement the only abstract method.
The following code shows how to invoke Timer.schedule()
a method that requires a TimerTask object as an argument:
var Timer = Java.type ("Java.util.Timer");
Timer.schedule (function () {print ("Hello world!")});
Attention:
The previous syntax assumes that the required SAM type is an interface or contains a default constructor that Nashorn uses to initialize a subclass. Here is the inability to use a class that does not contain a default constructor.
6, extend the specific Java class
To avoid confusion, the syntax for extending an abstract class cannot be used to extend a specific class. Because a specific class can be instantiated, such syntax is resolved to attempt to create a new class instance and pass the object of the class that the constructor requires (if the expected object type is an interface). To illustrate this issue, take a look at the following sample code:
var t = new Java.lang.Thread ({run:function () {print ("Thread running!")}});
This line of code is parsed to extend the Thread
class and implement the run()
method, and Thread
the instantiation of the class is an object that implements the Runnable interface by passing it to its constructor.
To extend a specific class, pass its type object to the Java.extend()
function, and then return the type object of its subclass. You can then use the type object of this subclass to create an instance and provide additional method implementations.
The following code shows you how to extend the Thread
class and implement the run()
method:
var Thread = Java.type ("Java.lang.Thread");
var threadextender = java.extend (Thread);
var t = new Threadextender () {
run:function () {print ("Thread running!")}};
Java.extend()
function to get a list of more than one type of object. You can specify no more than one Java type Object, or you can specify as many types of objects as Java interfaces. The returned type object extends the specified class (or java.lang.Object
, if no type object is specified), and the class implements all the interfaces. Class type objects do not have to be ranked first in the list.
7, access to the superclass (parent class) method
Methods that want to access the parent class can use Java .super()
functions.
The following example shows how to extend java.lang.Exception
a class and access the methods of the parent class.
Example 3-1 methods to access the parent class (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 (exception);
Return _super_.getmessage (). toUpperCase ();
}
try {
throw exception;
} catch (ex) {
print (exception);
}
If you run the above code, you will print the following:
Jdk.nashorn.javaadapters.java.lang.Exception:MY Exception Message
8, binding implementation to the class
In the previous section we described how to extend the Java class and use an additional JavaScript object parameter to implement the interface. An implementation is a specific instance of a binding, and this instance is created by new, not the entire class. There are some benefits to doing this, such as the memory footprint at run time, because Nashorn can create a single universal adapter for each implemented type combination.
The following example shows that different instances can be of the same Java class, and that their JavaScript implementation objects are different:
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 ();
Print ("We share the same class:" + (R1.class = = R2.class));
The above code prints the following results:
I ' m runnable 1!
I ' m runnable 2!
We share the same class:true
If you want to pass an instance of a class to an external API (such as the JavaFX framework, pass a application instance to the JavaFX API), you must extend a Java class or implement an interface bound to that class, rather than an instance of it. You can pass a JavaScript object to bind the implementation class and pass it to the last parameter of the Java.extend () function. This creates a new class that contains the same constructor as the original class, because they do not require additional object parameters to be implemented.
The following example shows how to bind the implementation into a class and demonstrate that in this case the implementation classes for different invocations are different:
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 (); var r2 = new RunnableImpl2 ();
R1.run ();
R2.run ();
Print ("We share the same class:" + (R1.class = = R2.class));
The above example performs the following results:
I ' m runnable 1!
I ' m runnable 2!
We share the same class:false
Moving an implementation object from a constructor call to a Java.extend()
function call avoids the extra parameters required in the constructor call. Each Java.extend()
call to a function requires an implementation object of the specified class to generate a new Java adapter class. An adapter class with a class boundary implementation can still use an additional constructor parameter to further override the behavior of a particular instance. So you can combine the two methods: you can provide a partial JavaScript implementation in a base class, pass it to a Java.extend()
function, and provide an instance implementation in an object and pass it to the constructor. object defines some function definitions when it is passed to the constructor.
The following code shows how to override a function of a class boundary object by passing a function to the constructor:
var Runnableimpl = java.extend (java.lang.Runnable, function () {print ("I ' m Runnable 1!")});
var r1 = new Runnableimpl ();
var r2 = new Runnableimpl (function () {print ("I ' m runnable 2!")});
R1.run ();
R2.run ();
Print ("We share the same class:" + (R1.class = = R2.class));
The above example prints the results as follows:
I ' m runnable 1!
I ' m runnable 2!
We share the same class:true
9. Select method Overload variant
Java methods can be overloaded by using different parameter types. The Java compiler (JAVAC) chooses the correct method to execute at compile time. Executed when the parsing method of the Java overloaded method is invoked in Nashorn. It is also based on the parameter type to determine the correct method. But if the actual parameter type leads to ambiguity, we can explicitly specify a specific overload variant. This increases the performance of the program, because the Nashorn engine does not have to identify which method to call during the call.
The overloaded variant is exposed as a special attribute. We can refer to them in the form of strings, which contain method names, parameter types, and both are surrounded by parentheses.
The following example shows how to invoke System.out.println()
Object
a variant of the method with parameters, and we pass a "hello" string to it:
var out = Java.lang.System.out;
out["println (Object)"] ("Hello");
In the example above, the use of the Object class name is sufficient because it is uniquely identifying the correct signature. You must use the full class name in case the two overloaded variant functions use different parameter types, but the names of the types are the same (this is possible, for example, different packages contain the same class name).
10. Mapping Data types
Most Java and JavaScript transitions before are as good as you expect. In the previous section we mentioned some simple data type mappings between Java and JavaScript. For example, you can explicitly convert array type data, which can be automatically converted to a SAM type when passed as a parameter to a Java method. Each JavaScript object implements an java.util.Map
interface to allow the API to accept mappings directly. When a numeric value is passed to the Java API, it is converted to the expected target numeric type, either as a package type or as a raw data type. If the target type is not sure (such as number), you can only ask that it must be a number type, and then specifically for the type that encapsulates a Double, an Integer, or a Long, and so on. Internal optimizations allow numeric values to be of any package type. Colleague you can pass any JavaScript value to the Java API, either encapsulated or original, because JavaScript's ToNumber
conversion algorithm will automatically process its value. If the Java method requires one String
or an Boolean
object parameter, JavaScript will use ToString
and ToBoolean
transform to get its value.
Attention:
Because the internal performance optimizations for string operations are considered, JavaScript strings do not always correspond to java.lang.String types or java.lang.CharSequence
types. If you pass a JavaScript string to a java.lang.String
Java method that requires parameters, then the JavaScript string is the java.lang.String
type, but if your method signature wants to be more generic (for example, the accepted parameter type is Java.lang.Object), then the parameter object you get will make an CharSequence
object that implements the class, not a Java string object.
Summarize
The above is the entire content of this article, I hope that everyone's study and work can have some help, if there is doubt you can message exchange.