The Java Programming Language

I shall present an overview of the Java language and a brief description of the Java virtual machine|this will not be a tutorial. For a good Java tutorial and reference, I refer you to [Fla96]. There will be a brief summary and the odd snide remark about network computers. Chapter 1 History Java started o as a control language for embedded systems (c.1990)|the idea was to unite the heterogenous microcontrollers used in embedded appliances (initially mainly consumer electronics) with a common language (the Java Virtual Machine (JVM)) and API so that manufacturers wouldn't have to change their software whenever a new microcontroller came on the market. It was realised that the JVM would work just as well over the internet, and the JVM (and the Java language that was developed in association with it) was pushed as a vehicle for active web content. More recently, the Java bandwagon has acquired such initiatives as the network computer, personal and embedded Java (which take Java back to its roots as an embedded control system), and are being pushed as tools for developing `serious' applications. Unfortunately, the Java bandwagon has also acquired a tremendous amount of hype, snake-oil, and general misinformation. It is being used by Sun as a weapon in its endless and byzantine war with Microsoft, and has pioneered the industry acceptance of vapourware sales (whereby people pay to licence technologies which don't exist yet). The typical lead time for a Java technology is six months (that is, the period between it being announced as available and shipping is usually circa six months). It will be useful to keep this in mind. Most terms to do with Java are trademarks of Sun Microsystems, who controls them in the somewhat vain hope of being able to maintain some degree of standardisation. I shall refer to the JDK, by which I mean Sun's Java Development Kit, the standard Java compiler and runtime environment. 2 Chapter 2 The Java Language As mentioned in the previous section, Java is really a remote execution system, broken into two parts|Java and the Java Virtual Machine. The two are pretty much inseparable. Java has a C/C++-based syntax, inheriting the nomenclature of classes, the private, public, and protected nomenclature, and its concepts of constructors and destructors, from C++. It also borrows heavily from the family of languages that spawned Modula-3|to these it owes garbage collection, threads, exceptions, safety, and much of its inheritance model. Java introduces some new features of its own : Ubiquitous classes |classes and interfaces (which are like classes, but are used to describe speci cations rather than type de nitions) are the only real structure in Java: everything from your window system to an element of your linked list will be a class. Dynamic loading |Java provides for dynamic class (and interface) loading (indeed, it would be di cult to produce a JVM implementation without it). Unicode (2.0) source format |Java source code is written in Unicode 2.0 ([The96])|internationalisation at last ? Labelled breaks {help solve a typical problem with the break construct|you sometimes want to exit more than one loop. We can write, eg: bool k = false; while (a) { while (b) { if (a->head==b->head) { k = true; break; } b=b->tail; 3 }if (k) { break; }; a=a->tail; } Becomes foo: while (a) { while (b) { if (a->head==b->head) { break foo; }b = b->tail; }a=a->tail; } Object-Orientated Synchronisation and exception handling |every object can be locked, waited on and signalled. Every object which is a subclass (in Modula-3 terms, a subtype) of java.lang.Exception may be thrown as an exception. Documentation Comments |There is a special syntax for `documentation comments' (/** ...*/), which may be used to automatically generate documentation from source les. Such tools are fairly primitive at present, and if you look at the automatically generated html documentation for the JDK libraries, you will nd that you need to scoot up and down the object heirarchy several times before very much of it begins to make sense. Widely-used exceptions |Java tends to raise an exception when it encounters a run-time error, rather than aborting your program|so, for example, attempting an out-of-bounds array access throws ArrayIndexOutOfBoundsException rather than aborting your program. It will be useful to note here that Java has complete safety|there are no untraced references, and no way to do pointer arithmetic. Anything unsafe must be done outside Java by another language, the results being communicated back via. the foreign language interface mechanism, native methods, which we will consider later. 2.1 Types Java has a fairly typical type system. As in Modula-3, there are two classes of types|base types and reference types.4 2.1.1 Base types The following categories of base types are de ned: Boolean: bool2 ftrue; falseg 1 Integral { byte 2 f 27 : : :27 1g { short 2 f 215 : : :215 1g { int 2 f 231 : : :231 1g { long 2 f 261 : : :261 1g { char 2 f0 : : :FFFF16g Floating point: IEEE 754 single precision (float), and IEEE 754 double precistion (double) oating point numbers. Note that there is no extended type, so you cannot use IEEE extended precision. You will observe a number of changes from C: No enumerations |the intended methodology is to use class (or interface) variables, eg. static int RED=1;. Hopefully, this will become clearer later. 16-bit char |char has been widened to 16 bits to accomodate Unicode characters. C programmers (and others who assume sizeof(char)==1) beware! No signed or unsigned |this avoids the problems that unsigned types always cause: either LAST(unsigned k) = 2*LAST(k)+1 (C), in which case implicit conversions to signed types can fail, or LAST(unsigned k) = LAST(signed k) (Modula-3) in which case you can never subtract two signed types and put their results in an unsigned variable (try Rect.Horsize(Rect.Full) and watch the pretty value out of range errors abort your program. . . ). 2.1.2 Reference types Reference types subsume classes, interfaces, objects and arrays. The Java equivalent of NIL is null, and the equivalent of ROOT is java.lang.Object. Note that we need no equivalent for ADDRESS, as there are no untraced references in Java, and we need no equivalent for REFANY as there are no records, and it turns out that arrays are also objects2. 1This is the only type that doesn't exist in the JVM|see 3. 2though this is obviously not explicit, since it would introduce parametric polymorphism into the type system. It is, however, possible to introduce parametric polymorphism, as we shall see later in our discussion of Pizza. 5 2.2 Operators and conversion With Java's syntax lifted mostly from C and C++, it is no surprise to nd that it shares many of the same operators for base types: < <= > >= == != && || return a boolean. + * / % ++ -<< >> >>> ~ & | ^ ?: ++ -+= -= *= /= &= |= =̂ %= <<= >>= >>>= instanceof is a binary operator (a instanceof T) which returns a boolean| true if a is of type T, and false otherwise. Conversion is done by typecasting, as in C, using ( and ). .. and + can also be used for strings ("foo" + "bar"). You will note that the comparison operators now return a boolean, and that Java has standardised (mainly through not having unary *) the behaviour of *=. There is also a new right shift operator, >>>, meaning `arithmetic shift right', some syntactic sugar for concatenating strings, and instanceof and casting replace ISTYPE and NARROW respectively. The `+' syntax for strings is similar to & in Modula-3; note, however, that Java distinguishes between constant strings (of class java.lang.String) and mutable strings (of class java.lang.StringBuffer). "a" + "b" produces a new String, "ab". Integer and oating-point operations with mixed-precision types (eg. int + long or float + double) implicitly convert all their arguments to the `widest' type present, and their results are of the type of their widest operand. Numerical analysts beware. . . There are actually several types of type conversion in Java: Identity conversions |the identity conversion. Assignment conversion |takes place when assigning a variable to the value of an expression. Primitive Widening conversion |widens a value of a base type to another base type with a greater range, and may also convert integer types to oating point types. Primitive Narrowing conversion |the inverse of primitive widening conversion (narrows to a type with a smaller range), and may also convert oating point types to integer types. Widening reference conversion |intuitively, converts an object of a given type to one of one of its supertypes. 6 Narrowing reference conversion |the inverse of widening reference conversion (the reference conversions are like NARROW() in Modula-3). String conversion |there is a conversion from any type to type String. Forbidden Conversions |some conversions are forbidden. Assignment Conversion |occurs during assignment. Method invocation conversion |occurs during method invocation. Casting conversion |occurs when the casting operator is used, eg. (Foo)bar. All of which are described in excruciating detail in x5 of [GS97]. The question of reference type equivalence is a little confused due to the presence of interfaces, but Java basically uses name-equivalence, in contrast with Modula-3's structural equivalence. 2.3 Imperative Constructs Java provides basically the same imperative constructs as C, but there are a few di erences (and surprises): Scoping |Java supports nested scopes (at last!), so { int i=1; if (i==1) { int k; k=4; } }Now works properly3. Indeed, you may even declare variables half way through a scope (though it is considered bad practice to do so): { int i; foo; int k; bar; } 3Java does not support implicit scoping in for...next loops, however, so your loop variables must still be declared in the enclosing scope, or the initialisation clause of the loop. 7 Is equivalent to: { int i; foo; { int k; bar; } }And it