Calling Java from Mathematica
Preamble
J/Link provides
Mathematica users with the ability to interact with arbitrary Java classes directly from
Mathematica. You can create objects and call methods directly in the
Mathematica language. You do not need to write any Java code, or prepare in any way the Java classes you want to use. You also do not need to know anything about
MathLink. In effect, all of Java becomes a transparent extension to
Mathematica, almost as if every existing and future Java class were written in the
Mathematica language itself.
This facility is called "installable Java" because it generalizes the ability that
Mathematica has always had to plug in extensions written in other languages through the
Install function. You will see later how
J/Link vastly simplifies this procedure for Java compared to languages like C or C++. In fact,
J/Link makes the procedure go away completely, which is why Java becomes a transparent extension to
Mathematica.
Although Java is often referred to as an interpreted language, this is really a misnomer. To use Java you must write a complete program, compile it, and then execute it (some environments exist that let you interactively execute lines of Java code, but these are special tools, and similar tools exist for traditional languages like C).
Mathematica users have the luxury of working in a true interpreted, interactive environment that lets them experiment with functions and build and test programs a line at a time.
J/Link brings this same productive environment to Java programmers. You could say that
Mathematica becomes a scripting language for Java.
To
Mathematica users, then, the "installable Java" feature of
J/Link opens up the expanding universe of Java classes as an extension to
Mathematica; for Java users, it allows the extraordinarily powerful and versatile
Mathematica environment to be used as a shell for interactively developing, experimenting with, and testing Java classes.
Loading the J/Link Package
The first step is to load the J/Link package file. |
Launching the Java Runtime
InstallJava
The next step is to launch the Java runtime and "install" it into
Mathematica. The function for this is
InstallJava.
| InstallJava[] | launch the Java runtime and prepare it for use from Mathematica |
| ReinstallJava[] | quit and restart the Java runtime if it is already running |
| JavaLink[] | give the LinkObject that is being used to communicate with the Java runtime |
Launching the Java runtime.
| Out[2]= |  |
InstallJava can be called more than once in a session. On every call after the first, it does nothing. Thus, it is safe to call
InstallJava in any program you write, without considering whether the user has already called it.
InstallJava creates a command line that is used to launch the Java runtime (typically called "java") and specify some initial arguments for it. In rare cases you will need to control what is on this command line, so
InstallJava takes a number of options for this purpose. Most users will not need to use these options, and in fact you should avoid them. Programmers should not assume that they have the ability to control the launch of the Java runtime, as it might already be running. If for some reason you absolutely must apply options to control the launch of the Java runtime, use
ReinstallJava instead of
InstallJava.
| ClassPath->None | use the default class path of your Java runtime |
| ClassPath->"dirs" | use the specified directories and jar files |
| CommandLine->"cmd" | use the specified command line to launch the Java runtime, instead of "java" |
Options for InstallJava.
Controlling the Command Used to Launch Java
An important option to
InstallJava and
ReinstallJava is
CommandLine. This specifies the first part of the command line used to launch Java. One use for this option is if you have more than one Java runtime installed on your system, and you want to invoke a specific one:
By default,
InstallJava will launch the Java runtime that is bundled with
Mathematica 4.2 and later. If you have an earlier version of
Mathematica, the default command line that will be used is
java on most systems. If the
java executable is not on your system path, you can use
InstallJava to point at it. Another use for this option is to specify arguments to Java that are not covered by other options. Here is an example that specifies verbose garbage collection and defines a property named
foo to have the value
bar.
Overriding the Class Path
The class path is the set of directories in which the Java runtime looks for classes. When you launch a Java program from your system's command line, the class path used by Java includes some default locations and any locations specified in the
CLASSPATH environment variable, if it exists. If you use the
-classpath command-line option to specify a set of locations, however, then the
CLASSPATH environment variable is ignored. The
ClassPath option to
InstallJava and
ReinstallJava works the same way. If you leave it at the default value,
Automatic, then
J/Link will include the contents of the
CLASSPATH environment variable in its class search path. If you set it to
None or a string, then the contents of
CLASSPATH are not used. If you set it to be a string, use the same syntax that you would use for setting the
CLASSPATH environment variable, which is different for Windows and Unix:
J/Link has its own mechanism for controlling the class search path that is very flexible. Not only does
J/Link automatically search for classes in
Mathematica application directories, it also lets you dynamically add new search locations while the Java runtime is running. This means that using the
ClassPath option to configure the class path when Java first launches is not very important. One setting for the
ClassPath option that is sometimes useful is
None, to prevent
J/Link from finding any classes from the contents of
CLASSPATH. You might want to do this if you had an experimental version of some class in a development directory and you wanted to make sure that
J/Link used that version in preference to an older one that was present on your
CLASSPATH. "
The Java Class Path" presents a complete treatment of the subject of how
J/Link searches for classes, and how to add locations to this search path.
Loading Classes
LoadJavaClass
| LoadJavaClass["classname"] | load the specified class into Java and Mathematica |
| LoadClass["classname"] | deprecated name from earlier versions of J/Link; use LoadJavaClass instead |
Loading classes.
To use a Java class in
Mathematica, it must first be loaded into the Java runtime and certain definitions must be set up in
Mathematica. This is accomplished with the
LoadJavaClass function.
LoadJavaClass takes a string specifying the fully qualified name of the class (i.e., the full hierarchical name with all the periods):
| Out[1]= |  |
The return value is an expression with head
JavaClass. This
JavaClass expression can be used in many places in
J/Link, so you might want to assign it to a variable as done here. Virtually everywhere in
J/Link where a class needs to be specified as an argument, you can use either a
JavaClass expression, the fully qualified class name as a string, or an object of the class. Note that you cannot create a valid
JavaClass expression by simply typing it in—it must be returned by
LoadJavaClass.
When a class has been loaded, you can call static methods in the class, create objects of the class, and invoke methods and access fields of these objects. You can use any
public constructors, methods, or fields of a class.
| StaticsVisible->True | make static methods and fields accessible by just their names, not in a special context |
| AllowShortContext->False | make static methods and fields accessible only in their fully qualified class context |
| UseTypeChecking->False | suppress the type checking that is normally inserted in definitions for calls into Java |
Options for LoadJavaClass.
"
The Java Class Path" discusses the details of how and where
J/Link finds classes.
J/Link will be able to find classes on the class path, in the special Java extensions directory, and in a set of extra directories that users can control even while
J/Link is running.
When to Call LoadJavaClass
It is often the case that you do not need to explicitly load a class with
LoadJavaClass. As described later, when you create a Java object with
JavaNew, you can supply the class name as a string. If the class has not already been loaded,
LoadJavaClass will be called internally by
JavaNew. In fact, anytime a Java object is returned to
Mathematica its class is loaded automatically if necessary. This would seem to imply that there is little reason to use
LoadJavaClass. There are a number of reasons why you would want or need to use
LoadJavaClass explicitly:
- You need to call a static method of a class and you will not create, or have not yet created, an object of that class. A class must be loaded before any of its static methods can be called.
- You want to see errors associated with loading a class reported at a well-defined time.
- You want to control where your users experience the initial delay associated with loading a class. Loading a class can take several seconds if it or one of its parent classes is very large (although it rarely takes that long). You might want to avoid a mysterious delay in a function that users expect to be very quick.
- You want to hang on to the JavaClass expression returned by LoadJavaClass to use it in other functions. Although all functions that take a JavaClass can also take a class name string, you might prefer to use a named JavaClass variable for readability purposes. It is also slightly faster than using a string, but this will not be perceptible unless you are using it many times in a loop.
- You feel that it makes your code more self-documenting.
The operation of loading a class in
J/Link is only done once in a
J/Link session (a session is the period between
InstallJava and
UninstallJava). You can call
LoadJavaClass on a given class as many times as you want, and every call after the first one immediately returns the
JavaClass expression without doing any work. This is important, as it means that you never have to worry whether a class has been loaded already—if you are not sure, call
LoadJavaClass.
Developers writing code for a wide audience should always call
LoadJavaClass on any classes they need in every function that needs them. It is not suitable to call
LoadJavaClass in the body of your package code when it is read in, as the user may quit and restart the Java runtime (i.e.,
UninstallJava and
InstallJava) after your package was read. To be safe, every user-level function that uses
J/Link should call
InstallJava and
LoadJavaClass (if
LoadJavaClass is necessary; see the following). Both calls execute very quickly if they are not needed.
As mentioned already, loading a class can take several seconds in some cases. When a class is loaded, all of its superclasses are loaded in succession, walking up the inheritance hierarchy. Because a given class is only actually loaded once, if you load another class that shares some of the same superclasses as a previously loaded class, these superclasses will not have to be loaded again. This means that loading the second class will be much quicker than the first if any of the shared superclasses were large. An example of this is loading classes in the java.awt package. The class
java.awt.Component is very large, so the first time you load a class that inherits from it, say
java.awt.Button, there will be a noticeable delay. Subsequent loading of other classes derived from
Component will be much quicker.
Contexts and Visibility of Static Members
LoadJavaClass has two options that let you control the naming and visibility of static methods and fields. To understand these options, you need to understand the problems they help to solve. This explanation gets a bit ahead since how to call Java methods has not been discussed. When a class is loaded, definitions are created in
Mathematica that allow you to call methods and access fields of objects of that class. Static members are treated quite differently from nonstatic ones. None of these issues arise for nonstatic members, so only static members are discussed in this section. Say you have a class named
com.foobar.MyClass that contains a static method named
foo. When you load this class, a definition must be set up for
foo so that it can be called by name, something like
foo[args]. The question becomes: In what context do you want the symbol
foo defined, and do you want this context to be visible (i.e., on
$ContextPath)?
J/Link always creates a definition for
foo in a context that mirrors its fully qualified classname:
com`foobar`MyClass`foo. This is done to avoid conflicting with symbols named
foo that might be present in other contexts. However, you might find it clumsy to have to call
foo by typing the full context name every time, as in
com`foobar`MyClass`foo[args]. The option
AllowShortContext->True (this is the default setting) causes
J/Link to also make definitions for
foo accessible in a shortened context, one that consists of just the class name without the hierarchical package name prefix. In the example, this means that you could call
foo as simply
MyClass`foo[args]. If you need to avoid use of the short context because there is already a context of the same name in your
Mathematica session, you can use
AllowShortContext->False. This forces all names to be put only in the "deep" context. Note that even with
AllowShortContext->True, names for statics are also put into the deep context, so you can always use the deep context to refer to a symbol if you desire.
AllowShortContext, then, lets you control the context where the symbol names are defined. The other option,
StaticsVisible, controls whether this context is made visible (put on
$ContextPath) or not. The default is
StaticsVisible->False, so you have to use a context name when referring to a symbol, as in
MyClass`foo[args]. With
StaticsVisible->True,
MyClass` will be put on
$ContextPath, so you could just write
foo[args]. Having the default be
True would be a bit dangerous—every time you load a class a potentially large number of names would suddenly be created and made visible in your
Mathematica session, opening up the possibility for all sorts of "shadowing" problems if symbols of the same names were already present. This problem is particularly acute with Java, because method and field names in Java typically begin with a lowercase letter, which is also the convention for user-defined symbols in
Mathematica. Some Java classes define static methods and fields with names like
x,
y,
width, and so on, so shadowing errors are very likely to occur (see "
Contexts" for a discussion of contexts and shadowing problems).
For these reasons
StaticsVisible->True is recommended only for classes that you have written, or ones whose contents you are familiar with. In such cases, it can save you some typing, make your code more readable, and prevent the all-too-easy bug of forgetting to type the package prefix. A classic example would be implementing the venerable "addtwo"
MathLink example program. In Java, it might look like this:
public class AddTwo {
public static int addtwo(int i, int j) {return i + j;}
}
With the default
StaticsVisible->False, you would have to call addtwo as
AddTwo`addtwo[3, 4]. Setting
StaticsVisible->True lets you write the more obvious
addtwo[3, 4].
Be reminded that these options are only for
static methods and fields. As discussed later, nonstatics are handled in a way that makes context and visibility issues go away completely.
Inner Classes
Inner classes are public classes defined inside another public class. For example, the class
javax.swing.Box has an inner class named
Filler. When you refer to the
Filler class in a Java program, you typically use the outer class name, followed by a period, then the inner class name:
Box.Filler f = new Box.Filler(...);
You can use inner classes with
J/Link, but you need to use the true internal name of the class, which has a
$, not a period, separating the outer and inner class names:
If you look at the class files produced by the Java compiler, you will see these
$-separated class names for inner classes.
Conversion of Types Between Java and Mathematica
Before you encounter the operations of creating Java objects and calling methods, you should examine the mapping of types between
Mathematica and Java. When a Java method returns a result to
Mathematica, the result is automatically converted into a
Mathematica expression. For example, Java integer types (e.g., byte, short, int, and so on), are converted into
Mathematica integers, and Java real number types (float, double) are converted into
Mathematica reals. The following table shows the complete set of conversions. These conversions work both ways—for example, when a
Mathematica integer is sent to a Java method that requires a byte value, the integer is automatically converted to a Java byte.
| |
| byte, char, short, int, long | Integer |
| Byte, Character, Short, Integer, Long, BigInteger |
| Integer |
| float, double | Real |
| Float, Double, BigDecimal | Real |
| boolean | True or False |
| String | String |
| array | List |
| controlled by user (see "Complex Numbers") | Complex |
| Object | JavaObject |
| Expr | any expression |
| null | Null |
Corresponding types in Java and Mathematica.
Java arrays are mapped to
Mathematica lists of the appropriate depth. Thus, when you call a method that takes a
double[], you might pass it
{1.0, 2.0, N[Pi], 1.23}. Similarly, a method that returns a two-deep array of integers (i.e.,
int[][]) might return to
Mathematica the expression
{{1, 2, 3}, {5, 3, 1}}.
In most cases,
J/Link will let you supply a
Mathematica integer to a method that is typed to take a real type (
float or
double). Similarly, a method that takes a
double[] could be passed a list of mixed integers and reals. The only times when you cannot do this are the rare cases where a method has two signatures that differ only in a real versus integer type at the same argument slot. For example, consider a class with these methods:
public void foo(byte b, Object obj);
public void foo(float f, Object obj);
public void bar(float f, Object obj);
J/Link would create two
Mathematica definitions for the method
foo—one that required an integer for the first argument and invoked the first signature, and one that required a real number for the first argument and invoked the second signature. The definition created for the method
bar would accept an integer or a real for the first argument. In other words,
J/Link will automatically convert integers to reals, except in cases where such conversion makes it ambiguous as to which signature of a given method to invoke. This is not strictly true, though, as
J/Link does not try as hard as it possibly could to determine whether real versus integer ambiguity is a problem at every argument position. The presence of ambiguity at one position will cause
J/Link to give up and require exact type matching at all argument positions. This is starting to sound confusing, but you will find that in most cases
J/Link allows you to pass integers or lists with integers to methods that take reals or arrays of reals, respectively, as arguments. In cases where it does not, the call will fail with an error message, and you will have to use
Mathematica's
N function to convert all integers to reals explicitly.
Creating Objects
To instantiate Java objects, use the
JavaNew function. The first argument to
JavaNew is the object's class, specified either as a
JavaClass expression returned from
LoadJavaClass or as a string giving the fully qualified class name (i.e., having the full package prefix with all the periods). If you wish to supply any arguments to the object's constructor, they follow as a sequence after the class.
| JavaNew[cls,arg1,...] | construct a new object of the specified class and return it to Mathematica |
| JavaNew["classname",arg1,...] | construct a new object of the specified class and return it to Mathematica |
Constructing Java objects.
For example, this will create a new Frame.
| Out[1]= |  |
|
The return value from
JavaNew is a strange expression that looks like it has the head
JavaObject, except that it is enclosed in angle brackets. The angle brackets are used to indicate that the form in which the expression is displayed is quite different from its internal representation. These expressions will be referred to as
JavaObject expressions.
JavaObject expressions are displayed in a way that shows their class name, but you should consider them opaque, meaning that you cannot pick them apart or peer into their insides. You can only use them in
J/Link functions that take
JavaObject expressions. For example, if
obj is a
JavaObject, you cannot use
First[obj] to get its class name. Instead, there is a
J/Link function,
ClassName[obj], for this purpose.
JavaNew invokes a Java constructor appropriate for the types of the arguments being passed in, and then returns to
Mathematica what is, in effect, a reference to the object. That is how you should think of
JavaObject expressions—as references to Java objects very much like object references in the Java language itself. What is returned to
Mathematica is not large no matter what type of object you are constructing. In particular, the object's data (that is, its fields) are not sent back to
Mathematica. The actual object remains on the Java side, and
Mathematica gets a reference to it.
The Frame class has a second constructor, which takes a title in the form of a string. Here is how you would call that constructor.
| Out[2]= |  |
|
Note that simply constructing a
Frame does not cause it to appear. That requires a separate step (calling the frame's
show or
setVisible methods will work, but as you will see later,
J/Link provides a special function,
JavaShow, to make Java windows appear and come to the foreground).
The previous examples specified the class by giving its name as a string. You can also use a JavaClass expression, which is a special expression returned by LoadJavaClass that identifies a class in a particularly efficient manner. When you specify the class name as a string, the class is loaded if it has not already been. |
JavaNew is not the only way to get a reference to a Java object in
Mathematica. Many methods and fields return objects, and when you call such a method, a
JavaObject expression is created. Such objects can be used in the same way as ones you explicitly construct with
JavaNew.
At this point, you may be wondering about things like reference counts and how objects returned to
Mathematica get cleaned up. These issues are discussed in "
Object References in Mathematica".
J/Link has two other functions for creating Java objects, called
MakeJavaObject and
MakeJavaExpr. These specialized functions are described in the section
"MakeJavaObject and MakeJavaExpr".
Calling Methods and Accessing Fields
Syntax
The
Mathematica syntax for calling Java methods and accessing fields is very similar to Java syntax. The following box compares the
Mathematica and Java ways of calling constructors, methods, fields, static methods, and static fields. You can see that
Mathematica programs that use Java are written in almost exactly the same way as Java programs, except
Mathematica uses
[] instead of
() for arguments, and
Mathematica uses
@ instead of Java's
. (dot) as the "member access" operator.
An exception is that for static methods,
Mathematica uses the context mark
` in place of Java's dot. This parallels Java usage also, as Java's use of the dot in this circumstance is really as a scope resolution operator (like
:: in C++). Although
Mathematica does not use this terminology, its scope resolution operator is the context mark. Java's hierarchical package names map directly to
Mathematica's hierarchical contexts.
| | |
| Java: | MyClass obj=new MyClass(args); |
| Mathematica: | obj=JavaNew["MyClass",args]; |
| | |
| Java: | obj.methodName(args); |
| Mathematica: | obj@methodName[args] |
| | |
| Java: | obj.fieldName=1;
value=obj.fieldName; |
| Mathematica: | obj@fieldName=1;
value=obj@fieldName; |
| | |
| Java: | MyClass.staticMethod(args); |
| Mathematica: | MyClass`staticMethod[args]; |
| | |
| Java: | MyClass.staticField=1;
value=MyClass.staticField; |
| Mathematica: | MyClass`staticField=1;
value=MyClass`staticField; |
Java and Mathematica syntax comparison.
You may already be familiar with
@ as a
Mathematica operator for applying a function to an argument:
f@x is equivalent to the more commonly used
f[x].
J/Link does not usurp
@ for some special operation—it is really just normal function application slightly disguised. This means that you do not have to use
@ at all. The following are equivalent ways of invoking a method:
The first form preserves the natural mapping of Java's syntax to
Mathematica's, and it will be used exclusively in this tutorial.
When you call methods or fields and get results back,
J/Link automatically converts arguments and results to and from their
Mathematica representations according to the table in "
Conversion of Types between Java and Mathematica".
Method calls can be chained in
Mathematica just like in Java. For example, if
meth1 returns a Java object, you could write in Java
obj.meth1().meth2(). In
Mathematica, this becomes
obj@meth1[]@meth2[]. Note that there is an apparent problem here:
Mathematica's
@ operator groups to the right, whereas Java's dot groups to the left. In other words,
obj.meth1().meth2() in Java is really
(obj.meth1()).meth2() whereas
obj@meth1[]@meth2[] in
Mathematica would normally be
obj@(meth1[]@meth2[]). I say "normally" because
J/Link automatically causes chained calls to group to the left like Java. It does this by defining rules for
JavaObject expressions, not by altering the properties of the
@ operator, so the global behavior of
@ is not affected. This chaining behavior only applies to method calls, not fields. You cannot do this:
You would have to split these up into two lines. For example, the second line above would become:
In Java, like other object-oriented languages, method and field names are scoped by the object on which they are called. In other words, when you write
obj.meth(), Java knows that you are calling the method named
meth that resides in
obj's class, even though there may be other methods named
meth in other classes.
J/Link preserves this scoping for
Mathematica symbols so that there is never a conflict with existing symbols of the same name. When you write
obj@meth[], there is no conflict with any other symbols named
meth in the system—the symbol
meth used by
Mathematica in the evaluation of this call is the one set up by
J/Link for this class. Here is an example using a field. First, you create a
Point object.
| Out[1]= |  |
The
Point class has fields named
x and
y, which hold its coordinates. A user's session is also likely to have symbols named
x or
y in it, however. You set up a definition for
x that will tell you when it is evaluated.
Now set a value for the field named
x (this would be written as
pt.x = 42 in Java).
You will notice that "gotcha" was not printed. There is no conflict between the symbol
x in the
Global` context that has the
Print definition and the symbol
x that is used during the evaluation of this line of code.
J/Link protects the names of methods and fields on the right-hand side of
@ so that they do not conflict with, or rely on, any definitions that might exist for these symbols in visible contexts. Here is a method example that demonstrates this issue differently.
Even though a new symbol
show is being created here, the
show that is used by
J/Link is the one that resides down in the
java`awt`Frame context, which has the necessary definitions set up for it.
In summary, for nonstatic methods and fields, you never have to worry about name conflicts and shadowing, no matter what context you are in or what the
$ContextPath is at the moment. This is not true for static members, however. Static methods and fields are called by their full name, without an object reference, so there is no object out front to scope the name. Here is a simple example of a static method call that invokes the Java garbage collector. You need to call
LoadJavaClass before you call a static method to make sure the class has been loaded.
The name scoping issue is not usually a problem with statics, because they are defined in their own contexts (
Runtime` in this example). These contexts are usually not on
$ContextPath, so you do not have to worry that there is a symbol of the same name in the
Global` context or in a package that has been read. There is more discussion of this issue in the
section on
LoadJavaClass, because
LoadJavaClass takes options that determine the contexts in which static methods are defined and whether or not they are put on
$ContextPath. If there is already a context named
Runtime` in your session, and it has its own symbol
gc, you can always avoid a conflict by using the fully hierarchical context name that corresponds to the full class name for a static member.
Finally, just as in Java, you can call a static method on an object if you like. In this case, since there is an object out front, you get the name scoping. Here you call a static method of the
Runtime class that returns the current
Runtime object (you cannot create a
Runtime object with
JavaNew, as
Runtime has no constructors). You then invoke the (static) method
gc on the object, and you can use
gc without any context prefix.
Underscores in Java Names
Java names can have characters in them that are not legal in
Mathematica symbols. The only common one is the underscore.
J/Link maps underscores in class, method, and field names to "U". Note that this mapping is only used where it is necessary—when names are used in symbolic form, not as strings. For example, assume you have a class named
com.acme.My_Class. When you refer to this class name as a string, you use the underscore.
But when you call a static method in such a class, the hierarchical context name is symbolic, so you must convert the underscore to
U.
The same rule applies to method and field names. Many Java field names have underscores in them, for example
java.awt.Frame.TOP_ALIGNMENT. To refer to this method in code, use the
U.
| Out[2]= |  |
In cases where you supply a string, leave the underscore.
Out[3]//TableForm= |
| |  |
Getting Information about Classes and Objects
J/Link has some useful functions that show you the constructors, methods, and fields available for a given class or object.
| Constructors[cls] | return a table of the public constructors and their arguments |
| Constructors[obj] | constructors for this object's class |
| Methods[cls] | return a table of the public methods and their arguments |
| Methods[cls,"pat"] | show only methods whose names match the string pattern pat |
| Methods[obj] | show methods for this object's class |
| Fields[cls] | return a table of the public fields |
| Fields[cls,"pat"] | show only fields whose names match the string pattern pat |
| Fields[obj] | show fields for this object's class |
| ClassName[cls] | return, as a string, the name of the class represented by cls |
| ClassName[obj] | return, as a string, the name of this object's class |
| GetClass[obj] | return the JavaClass representing this object's
class |
| ParentClass[obj] | return the JavaClass representing this object's
parent class |
| InstanceOf[obj,cls] | return True if this object is an instance of cls, False otherwise |
| JavaObjectQ[expr] | return True if expr is a valid reference to a Java object, False otherwise |
Getting information about classes and objects.
You can give an object or a class to
Constructors,
Methods, and
Fields. The class can be specified either by its full name as a string, or as a
JavaClass expression:
The declarations returned by these functions have been simplified by removing the Java keywords
public,
final (removed only for methods, not fields),
synchronized,
native,
volatile, and
transient. The declarations will always be public, and the other modifiers are probably not relevant for use via
J/Link.
Methods and
Fields take one option,
Inherited, which specifies whether to include members inherited from superclasses and interfaces or show only members declared in the class itself. The default is
Inherited->True.
| Inherited->False | show only members that are declared in the class itself, not inherited from superclasses or interfaces |
Option for Methods and Fields.
There are additional functions that give information about objects and classes. These functions are
ClassName,
GetClass,
ParentClass,
InstanceOf, and
JavaObjectQ. They are self-explanatory, for the most part. The
InstanceOf function mimics the Java language's
instanceof operator.
JavaObjectQ is useful for writing patterns that match only valid Java objects:
JavaObjectQ returns
True if and only if its argument is a valid reference to a Java object or if it is the symbol
Null, which maps to Java's
null object.
Quitting or Restarting Java
When you are finished with using Java in a
Mathematica session, you can quit the Java runtime by calling
UninstallJava[].
Quitting the Java runtime.
In addition to quitting Java,
UninstallJava clears out the many symbols and definitions created in
Mathematica when you load classes. All outstanding
JavaObject expressions will become invalid when Java is quit. They will no longer satisfy
JavaObjectQ, and they will show up as raw symbols like
JLink`Objects`JavaObject12345678 instead of
<<JavaObject[classname]>>.
Most users will have no reason to call
UninstallJava. You should think of the Java runtime as an integral part of the
Mathematica system—start it up, and then just leave it running. All code that uses
J/Link shares the same Java runtime, and there may be packages that you are using that make use of Java without you even knowing it. Shutting down Java might compromise their functionality. Developers writing packages should
never call
UninstallJava in their packages. You cannot assume that when your application is done with
J/Link, your users are done with it as well.
About the only common reason to need to stop and restart Java is when you are actively developing Java classes that you want to call from
Mathematica. Once a class is loaded into the Java runtime, it cannot be unloaded. If you want to modify and recompile your class, you need to restart Java to reload the modified version. Even in this circumstance, though, you will not be calling
UninstallJava. Instead, you will call
ReinstallJava, which simply calls
UninstallJava followed by
InstallJava again.
Version Information
J/Link provides three symbols that supply version information. These symbols provide the same type of information as their counterparts in
Mathematica itself, except that they are in the
JLink`Information` context, which is not on
$ContextPath, so you must specify them by their full names.
| JLink`Information`$Version | a string giving full version information |
| JLink`Information`$VersionNumber | a real number giving the current version number |
| JLink`Information`$ReleaseNumber | an integer giving the release number (the last digit in a full x.x.x version specification) |
| ShowJavaConsole[] | the console window will show version information for the Java runtime and the J/Link Java component |
J/Link version information.
| Out[1]= |  |
| Out[2]= |  |
| Out[3]= |  |
The
ShowJavaConsole[] function, described in
"The Java Console Window", will also display some useful version information. It shows the version of the Java runtime being used and the version of the portion of
J/Link that is written in Java. The version of the
J/Link Java component should match the version of the
J/Link Mathematica component.
Controlling the Class Path: How J/Link Finds Classes
The Java Class Path
The class path tells the Java runtime, compiler, and other tools where to find third-party and user-defined classes—classes that are not Java "extensions" or part of the Java platform itself. The class path has always been a source of confusion among Java users and programmers.
Java can find classes that are part of the standard Java platform (so-called "bootstrap" classes), classes that use the so-called "extensions" mechanism, and classes on the class path, which is controlled by the
CLASSPATH environment variable or by command-line options when Java is launched.
J/Link can load and use any classes that the Java runtime can find through these normal mechanisms. In addition,
J/Link can find classes, resources, and native libraries that are in a set of extra locations, beyond what is specified on the class path at startup. This set of extra locations can be added to while Java is running.
J/Link provides two ways to alter the search path Java uses to find classes. The first way is via the
ClassPath option to
ReinstallJava. The second way, which is superior to modifying the class path at startup, is to add new directories and jar files to the special set of extra locations that
J/Link searches. These two methods will be described in the next two subsections.
Overriding the Startup Class Path
For a class to be accessible via the standard Java class path, one of the following must apply:
- It is inside a .zip or .jar file that is itself named on the class path.
- It is a loose class file that is in an appropriately nested directory beneath a directory that is on the class path.
"Appropriately nested" means that the class file must be in a directory whose hierarchy mirrors the full package name of the class. For example, assume that the directory c:\MyClasses is on the class path. If you have a class that is not in a package (there is no package statement at the beginning of the code), its class file should be put directly into c:\MyClasses. If you have a class that is in the package
com.acme.stuff, its class file would need to be in the directory c:\MyClasses\com\acme\stuff. Note that jar and zip files must be explicitly named on the class path—you cannot just toss them into a directory that is itself named on the class path. Directory issues are not relevant for jar and zip files, meaning that regardless of how hierarchically organized the classes inside a jar file are, you simply name the jar file itself on the class path and all the classes inside it can be found.
If you want to specify paths for classes that are not part of the standard Java platform or extensions, you can use the
ClassPath option to
ReinstallJava. The value that you supply for the
ClassPath option is a string that names the desired directories and zip or jar files. This string is platform-dependent; the paths are specified in the native style for your platform, and the separator character is a colon on Unix and a semicolon on Windows. Here are typical specifications:
The default setting for
ClassPath is
Automatic, which means to use the value of the
CLASSPATH environment variable. If you set
ClassPath to something else, then J/Link will ignore the
CLASSPATH environment variable—it will not be able to find those classes. In other words, if you use a
ClassPath specification, you lose the
CLASSPATH environment variable. This is similar to the behavior of the
-classpath command-line option to the Java runtime and compiler, if you are familiar with those tools.
It is recommended that users avoid the
ClassPath option. If you need the dynamic control that the
ClassPath option provides, you should use the more powerful and convenient
AddToClassPath mechanism, described in the next section. The most common reason for using the
ClassPath option is if you want to specifically prevent the contents of the
CLASSPATH environment variable from being used. To do this, set
ClassPath->None.
Dynamically Modifying the Class Path
One thing that is inconvenient about the standard Java class path is that it cannot be changed after the Java runtime has been launched.
J/Link has its own class loader that searches in a set of special locations beyond the standard Java class path. This gives
J/Link an extremely powerful and flexible means of finding classes. To add locations to this extra set, use the
AddToClassPath function.
| AddToClassPath["location",...] | add the specified directories or jar files to J/Link's class search path |
Adding classes to the search path.
After Java has been started, you can call
AddToClassPath whenever you wish, and it will take effect immediately. One convenient feature of this extra class search path is that if you add a directory, then any jar or zip files in that directory will be searched. This means that you do not have to name jar files individually, as you need to do with the standard Java class path. For loose class files, the nesting rules are the same as for the class path, meaning that if a class is in the package
com.acme.stuff, and you called
AddToClassPath["d:\\myClasses"], then you would need to put the class file into d:\MyClasses\com\acme\stuff.
Changes to the search path that you make with
AddToClassPath only apply to the current Java session. If you quit and restart java, you will need to call
AddToClassPath again.
In addition to the locations you add yourself with
AddToClassPath,
J/Link automatically includes any Java subdirectories of any directories in
<Mathematica dir>/AddOns/Applications and
<Mathematica dir>/AddOns/ExtraPackages. This feature is designed to provide extremely easy deployment for developers who create applications for
Mathematica that use Java and
J/Link for part of their implementation. This is described in "
Deploying Applications that use J/Link" in more detail, but even casual Java programmers who are writing classes to use with
J/Link can take advantage of it. Just create a subdirectory of AddOns/Applications, say MyStuff, create a Java subdirectory within it, and toss class or jar files into it.
J/Link will be able to find and use them. Of course, loose class files have to be placed into an appropriately nested subdirectory of the Java directory, corresponding to their package names (if any), as described.
The
AddToClassPath function was introduced in
J/Link 2.0. Previous versions of
J/Link had a variable called
$ExtraClassPath that specified a list of extra locations. You could add to this list like this:
$ExtraClassPath was deprecated in
J/Link 2.0, but it still works. One advantage of
$ExtraClassPath over using
AddToClassPath is that changes made to
$ExtraClassPath persist across a restart of the Java runtime.
Examining the Class Path
The
JavaClassPath function returns the set of directories and jar files in which
J/Link will search for classes. This includes all locations added with
AddToClassPath or
$ExtraClassPath, as well as Java subdirectories of application directories in any of the standard
Mathematica application locations. It does not display the jar files that make up the standard Java platform itself, or jar files in the Java extensions directory. Those classes can always be found by Java programs.
| JavaClassPath[] | gives the complete set of directories and jar files in which J/Link will search for classes |
Inspecting the class search path.
Using J/Link's Class Loader Directly
As stated earlier,
J/Link uses its own class loader to allow it to find classes and other resources in a dynamic set of locations beyond the startup class path. Essentially all the classes that you load using
J/Link that are not part of the Java platform itself will be loaded by this class loader. One consequence of this is that calling Java's
Class.forName() method from
Mathematica will often not work.
| Out[5]= |  |
The problem is that
Class.forName() finds classes using a default class loader, not the
J/Link class loader, and this default class loader does not know about the special directories in which
J/Link looks for classes (in fact, it does not even know about the startup class path, because of details of how
J/Link launches Java). If you are translating Java code into
Mathematica, or if you just want to get a
Class object for a given class, watch out for this problem. The fix is to force
J/Link's class loader to be used. One way to do this is to use the three-argument form of
Class.forName(), which allows you to specify the class loader to be used:
An easier way is to use the static
classFromName method of
JLinkClassLoader:
You should think of this
classFromName() method as being the replacement for
Class.forName(). When you find yourself wanting to obtain a
Class object from a class name given as a string, remember to use
JLinkClassLoader.classFromName().
Class.forName() is not very commonly found in Java code. One reason it is used is when an object needs to be created, but its class was not known at compile time. For example, the class name might come from a preferences file or be determined programmatically in some other way. Often, the very next line creates an instance of the class, like this:
// Java code
Class cls = Class.forName("SomeClassThatImplementsInterfaceX");
X obj = (X) cls.newInstance();
If you are translating code like this into a
Mathematica program, this operation can be performed simply by calling
JavaNew:
The point here is that for a very common usage of
Class.forName(), you do not have to translate it line-by-line into
Mathematica—you can duplicate the functionality by calling
JavaNew.
Performance Issues
Overhead of Calls to Java
The speed of Java programs is highly dependent on the Java runtime. On certain types of programs, for example, ones that spend most of their time in a tight number-crunching loop, the speed of Java can approach that of compiled, optimized C.
Java is a good choice for computationally intensive programs. Your mileage may vary, but do not rule out Java for any type of program before you have done some simple speed testing. For less demanding programs, where every ounce of speed is not necessary, the simplicity of using
J/Link instead of programming traditional
MathLink "installable" programs with C makes Java an obvious choice.
The speed issues with
J/Link are not, for the most part, the speed of Java execution. Rather, the bottleneck is the rate at which you can perform calls into Java, which is itself limited mainly by the speed of
MathLink and the processing that must be done in
Mathematica for each call into Java. The maximum rate of calls into Java is highly dependent on which operating system and which Java runtime you use. A fast Windows machine can perform more than 5000 Java method calls per second, and considerably more if they are static methods, which require less preprocessing in
Mathematica. On some operating systems the results will be less. You should keep in mind that there is a more or less fixed cost of a call into Java regardless of what