22.4 LiveConnect Data Types
To understand how LiveConnect does its
job of connecting JavaScript to Java, you have to understand the
JavaScript data types that LiveConnect uses. The following sections
explain these JavaScript data types. Although Internet Explorer uses
a different technology, an understanding of how LiveConnect works
will also help you understand the workings of IE. Some of the
LiveConnect data types described here have analogs in IE.
22.4.1 The JavaPackage Class
A package in Java is
collection of related Java classes. The JavaPackage class is a
JavaScript data type that represents a Java package. The properties
of a JavaPackage are the classes that the package contains (classes
are represented by the JavaClass class, which we'll see
shortly), as well as any other packages that the package contains.
There is a restriction on the JavaPackage class: you cannot use a
JavaScript for/in loop to obtain a complete list
of all packages and classes that a JavaPackage contains. This
restriction is the result of an underlying restriction in the Java
virtual machine.
All JavaPackage objects are contained
within a parent JavaPackage; the
Window property named
Packages is a top-level JavaPackage that serves as
the root of this package hierarchy. It has properties such as
java, sun, and
netscape, which are JavaPackage objects that
represent the various hierarchies of Java classes that are available
to the browser. For example, the JavaPackage
Packages.java contains the JavaPackage
Packages.java.awt. For convenience, every Window
object also has java, sun, and
netscape properties that are shortcuts to
Packages.java, Packages.sun,
and Packages.netscape. Thus, instead of typing
Packages.java.awt, you can simply type
java.awt.
To continue with the example, java.awt is a
JavaPackage object that contains JavaClass objects such as
java.awt.Button, which represents the
java.awt.Button class. But it also contains yet
another JavaPackage object, java.awt.image, which
represents the java.awt.image package in Java.
As you can see, the property naming scheme for the JavaPackage
hierarchy mirrors the naming scheme for Java packages. Note, however,
that there is one big difference between the JavaPackage class and
the actual Java packages that it represents. Packages in Java are
collections of classes, not collections of other packages. That is,
java.lang is the name of a Java package, but
java is not. So the JavaPackage object named
java does not actually represent a package in
Java -- it is simply a convenient placeholder in the package
hierarchy for other JavaPackage objects that do represent real Java
packages.
On most systems, Java classes are installed in files in a directory
hierarchy that corresponds to their package names. For example, the
java.lang.String class is stored in the file
java/lang/String.class. Actually, this file is
usually contained in a ZIP file, but the directory hierarchy is still
there, encoded within the archive. Therefore, instead of thinking of
a JavaPackage object as representing a Java package, you may find it
clearer to think of it as representing a directory or subdirectory in
the directory hierarchy of Java classes.
The JavaPackage class has a few shortcomings. There is no way for
LiveConnect to tell in advance whether a property of a JavaPackage
refers to a Java class or to another Java package, so JavaScript
assumes that it is a class and tries to load a class. Thus, when you
use an expression like java.awt, LiveConnect first
looks for a class file java/awt.class. It may
even search for this class over the network, causing the web server
to log a "404 File Not Found" error. If LiveConnect does
not find a class, it assumes that the property refers to a package,
but it has no way to ascertain that the package actually exists and
has real classes in it. This causes the second shortcoming: if you
misspell a class name, LiveConnect happily treats it as a package
name, rather than telling you that the class you are trying to use
does not exist.
22.4.2 The JavaClass Class
The JavaClass class is a
JavaScript data type that represents a
Java class. A JavaClass object does not have any properties of its
own -- all of its properties represent (and have the same name as)
the public static fields and methods of the represented Java class.
These public static fields and methods are sometimes called
class fields and class
methods , to indicate that they are associated with a class
rather than an object instance. Unlike the JavaPackage class,
JavaClass does allow the use of the for/in loop to
enumerate its properties. Note that JavaClass objects do not have
properties representing the instance fields and methods of a Java
class -- individual instances of a Java class are represented by
the JavaObject class, which is documented in the next section.
As we saw earlier, JavaClass objects are contained in JavaPackage
objects. For example, java.lang is a JavaPackage
that contains a System property. Thus,
java.lang.System is a JavaClass object,
representing the Java class java.lang.System .
This JavaClass object, in turn, has properties such as
out and in that represent
static fields of the java.lang.System class. You
can use JavaScript to refer to any of the standard Java system
classes in this same way. The java.lang.Double
class is named java.lang.Double (or
Packages.java.lang.Double), for example, and the
java.awt.Button class is
java.awt.Button.
Another
way to obtain a JavaClass object in JavaScript is to use the
getClass( ) function. Given any JavaObject object,
you can obtain a JavaClass object that represents the class of that
Java object by passing the JavaObject to getClass(
).[3]
[3] Don't confuse the JavaScript
getClass( ) function, which returns a JavaClass
object, with the Java getClass( ) method, which
returns a java.lang.Class object. Once you have a JavaClass object, there are several things you can do
with it. The JavaClass class implements the LiveConnect functionality
that allows JavaScript programs to read and write the public static
fields of Java classes and invoke the public static methods of Java
classes. For example, java.lang.System is a
JavaClass. We can read the value of a static field of
java.lang.System like this:
var java_console = java.lang.System.out;
Similarly, we might invoke a static method of
java.lang.System with a line like this one:
var java_version = java.lang.System.getProperty("java.version");
Recall that Java is a typed
language -- all fields and method arguments have types. If you
attempt to set a field or pass an argument of the wrong type, an
exception is thrown. (Or, in versions of JavaScript prior to 1.5, a
JavaScript error occurs.)
There is one more
important feature of the JavaClass class. You can use JavaClass
objects with the JavaScript new operator to create
new instances of Java classes -- i.e., to create
JavaObject objects. The syntax for doing
so is just as it is in JavaScript (and just as it is in Java):
var d = new java.lang.Double(1.23);
Finally, having created a JavaObject in this way, we can return to
the getClass( ) function and show an example of
its use:
var d = new java.lang.Double(1.23);
// Create a JavaObject
var d_class = getClass(d);
// Obtain the JavaClass of the JavaObject
if (d_class == java.lang.Double) ...;
// This comparison will be true
When working with standard system classes like this, you can
typically use the name of the system class directly rather than
calling getClass( ). The getClass( )
function is more useful in obtaining the class of a
non-system object, such as an applet instance.
Instead of referring to a JavaClass with a cumbersome expression like
java.lang.Double, you can define a variable that
serves as a shortcut:
var Double = java.lang.Double;This mimics the Java import statement and can
improve the efficiency of your program, since LiveConnect does not
have to look up the lang property of
java and the Double property of
java.lang.
22.4.3 The JavaObject Class
The
JavaObject class is a JavaScript data type that represents a Java
object. The JavaObject class is, in many ways, analogous to the
JavaClass class. As with JavaClass, a JavaObject has no properties of
its own -- all of its properties represent (and have the same
names as) the public instance fields and public instance methods of
the Java object it represents. As with JavaClass, you can use a
JavaScript for/in loop to enumerate all the
properties of a JavaObject object. The JavaObject class implements
the LiveConnect functionality that allows us to read and write the
public instance fields and invoke the public methods of a Java
object.
For example, if d is a JavaObject that represents
an instance of the java.lang.Double class, we
can invoke a method of that Java object with JavaScript code like
this:
n = d.doubleValue( );
Similarly, we saw earlier that the
java.lang.System class has a static field
out. This field refers to a Java object of class
java.io.PrintStream . In JavaScript, we can refer
to the corresponding JavaObject as:
java.lang.System.out
and we can invoke a method of this object like this:[4]
[4] The output of this line of code doesn't appear in the web
browser itself, but rather in the Java Console. In Netscape 6, select
Tasks


Console to see this window. java.lang.System.out.println("Hello world!");
A JavaObject object also allows us to read and write the public
instance fields of the Java object it represents. Neither the
java.lang.Double class nor the
java.io.PrintStream class used in the preceding
examples has any public instance fields, however. But suppose we use
JavaScript to create an instance of the
java.awt.Rectangle class:
r = new java.awt.Rectangle( );
Then we can read and write its public instance fields with JavaScript
code like the following:
r.x = r.y = 0;
r.width = 4;
r.height = 5;
var perimeter = 2*r.width + 2*r.height;
The beauty of LiveConnect is that it allows a Java object,
r, to be used just as if it were a JavaScript
object. Some caution is required, however: r is a
JavaObject and does not behave identically to regular JavaScript
objects. The differences will be detailed later. Also, remember that
unlike JavaScript, the fields of Java objects and the arguments of
their methods are typed. If you do not specify JavaScript values of
the correct types, you cause JavaScript errors or exceptions.
In Netscape 6.1 and later the JavaObject class makes methods
available by name and by name plus argument type, which is useful
when there are two or methods that share the same name but expect
different types of arguments. As we saw earlier in this chapter, if a
JavaObject o represents an object that has two
methods named "convert", the convert
property of o may refer to either of those
methods. In recent versions of LiveConnect, however,
o also defines properties that include the
argument types, and you can specify which version of the method you
want by including this type information:
var iconvert = o["convert(int)"]; // Get the method we want
iconvert(3); // Invoke it
Because the name of the property includes parentheses, you
can't use the regular "." notation to access it and
must express it as a string within square brackets. The JavaClass
type has the same capability for overridden static methods.
22.4.4 The JavaArray Class
The
final LiveConnect data type for
JavaScript is the JavaArray class. As you might expect by now,
instances of this class represent Java arrays and provide the
LiveConnect functionality that allows JavaScript to read the elements
of Java arrays. Like JavaScript arrays (and like Java arrays), a
JavaArray object has a length property
that specifies the number of elements it contains. The elements of a
JavaArray object are read with the standard JavaScript
[] array index operator. They can also be
enumerated with a for/in loop. You can use
JavaArray objects to access multidimensional arrays (actually
arrays of arrays), just as in JavaScript or Java.
For example, suppose we create an instance of the
java.awt.Polygon class:
p = new java.awt.Polygon( );
The JavaObject p has properties
xpoints and
ypoints that are JavaArray objects representing
Java arrays of integers. (To learn the names and types of these
properties, look up the documentation for
java.awt.Polygon in a Java reference manual.) We
can use these JavaArray objects to randomly initialize the Java
polygon with code like this:
for(var i = 0; i < p.xpoints.length; i++)
p.xpoints[i] = Math.round(Math.random( )*100);
for(var i = 0; i < p.ypoints.length; i++)
p.ypoints[i] = Math.round(Math.random( )*100);
22.4.5 Java Methods
The JavaClass and JavaObject classes
allow us to invoke static methods and instance methods, respectively.
In Netscape 3, Java methods were internally represented by a
JavaMethod object. In Netscape 4, however, Java methods are simply
native methods, like the methods of built-in JavaScript objects such
as String and Date.
When you're using Java
methods, remember that they expect a fixed number of arguments of
fixed types. If you pass the wrong number of arguments, or an
argument of the wrong type, you cause a JavaScript error.