Overview of Java

Java, which was developed at Sun Microsystems, has emerged over the last several years as the object-oriented programming language of choice. It includes the following concepts:

A Java virtual machine (JVM), which provides the fundamental basis for platform independence

Automated storage management techniques, the most visible of which is garbage collection

Language syntax that borrows from C and enforces strong typing

The result is a language easily learned by existing C programmers, but which remains truly object-oriented and efficient for application-level programs.

Java and Object-Oriented Programming Terminology

This section covers some basic terminology for discussing details of Java application development in the Oracle8i environment. The terms should be familiar to experienced Java programmers. A detailed discussion of object-oriented programming or of the Java language is beyond the scope of this book. Many texts, in addition to the complete language specification, are available at your bookstore and on the Internet. See "Java Information Resources" in the Preface, and "Suggested Reading" in the Oracle8i Java Stored Procedures Developer's Guide. for pointers to reference materials and for places to find Java-related information on the Internet.

Classes

All object-oriented programming languages support the concept of a class. As with a table definition, a class provides a template for objects that share common characteristics. Each class can contain the following:

Attributes--static or instance variables that each object of a particular class possesses.

Methods--you can invoke methods defined by the class or inherited by any classes extended from the class.

When you create an object from a class, you are creating an instance of that class. The instance contains the fields of an object, which are known as its data, or state. Figure 1-1 shows an example of an Employee class defined with two attributes: last name (lastName) and employee identifier (ID).

Figure 1-1 Classes and Instances

When you create an instance, the attributes store individual and private information relevant only to the employee. That is, the information contained within an employee instance is known only for that single employee. The example in Figure 1-1 shows two instances of employee--Smith and Jones. Each instance contains information relevant to the individual employee.

Attributes

Attributes within an instance are known as fields. Instance fields are analogous to the fields of a relational table row. The class defines the fields, as well as the type of each field. You can declare fields in Java to be static, public, private, protected, or default access.

Public, private, protected, or default access fields are created within each instance.

Static fields are like global variables in that the information is available to all instances of the employee class.

The language specification defines the rules of visibility of data for all fields. Rules of visibility define under what circumstances you can access the data in these fields.

Methods

The class also defines the methods you can invoke on an instance of that class. Methods are written in Java and define the behavior of an object. This bundling of state and behavior is the essence of encapsulation, which is a feature of all object-oriented programming languages. If you define an Employee class, declaring that each employee's id is a private field, other objects can access that private field only if a method returns the field. In this example, an object could retrieve the employee's identifier by invoking the Employee.getId() method.

In addition, with encapsulation, you can declare that the Employee.getId() method is private, or you can decide not to write an Employee.getId() method. Encapsulation helps you write programs that are reusable and not misused. Encapsulation makes public only those features of an object that are declared public; all other fields and methods are private. Private fields and methods can be used for internal object processing.

Class Hierarchy

Java defines classes within a large hierarchy of classes. At the top of the hierarchy is the Object class. All classes in Java inherit from the Object class at some level, as you walk up through the inheritance chain of superclasses. When we say Class B inherits from Class A, each instance of Class B contains all the fields defined in class B, as well as all the fields defined in Class A. For example, in Figure 1-2, the FullTimeEmployee class contains the id and lastName fields defined in the Employee class because it inherits from the Employee class. In addition, the FullTimeEmployee class adds another field, bonus, which is contained only within FullTimeEmployee.

You can invoke any method on an instance of Class B that was defined in either Class A or B. In our employee example, the FullTimeEmployee instance can invoke methods defined only within its own class, or methods defined within the Employee class.

Figure 1-2 Inheritance Hierarchy

Instances of Class B are substitutable for instances of Class A, which makes inheritance another powerful construct of object-oriented languages for improving code reuse. You can create new classes that define behavior and state where it makes sense in the hierarchy, yet make use of pre-existing functionality in class libraries.

Interfaces

Java supports only single inheritance; that is, each class has one and only one class from which it inherits. If you must inherit from more than one source, Java provides the equivalent of multiple inheritance, without the complications and confusion that usually accompany it, through interfaces. Interfaces are similar to classes; however, interfaces define method signatures, not implementations. The methods are implemented in classes declared to implement an interface. Multiple inheritance occurs when a single class simultaneously supports many interfaces.

Polymorphism

Assume in our Employee example that the different types of employees must be able to respond with their compensation to date. Compensation is computed differently for different kinds of employees.

FullTimeEmployees are eligible for a bonus

NonExemptEmployees get overtime pay

In traditional procedural languages, you would write a long switch statement, with the different possible cases defined.

If you add a new kind of Employee, you must update your switch statement. If you modify your data structure, you must modify all switch statements that use it. In an object-oriented language such as Java, you implement a method, compensationToDate(), for each subclass of Employee class that requires any special treatment beyond what is already defined in Employee class. For example, you could implement the compensationToDate() method of NonExemptEmployee, as follows:

The common usage of the method name compensationToDate() allows you to invoke the identical method on different classes and receive different results, without knowing the type of employee you are using. You do not have to write a special method to handle FullTimeEmployees and PartTimeEmployees. This ability for the different objects to respond to the identical message in different ways is known as polymorphism.

In addition, you could create an entirely new class that does not inherit from Employee at all--Contractor--and implement a compensationToDate() method in it. A program that calculates total payroll to date would iterate over all people on payroll, regardless of whether they were full-time, part-time, or contractors, and add up the values returned from invoking the compensationToDate() method on each. You can safely make changes to the individual compensationToDate() methods with the knowledge that callers of the methods will work correctly. For example, you can safely add new fields to existing classes.

The Java Virtual Machine (JVM)

As with other high-level computer languages, your Java source compiles to low-level machine instructions. In Java, these instructions are known as bytecodes (because their size is uniformly one byte of storage). Most other languages, such as C, compile to machine-specific instructions; for example, instructions specific to an Intel or HP processor. Your Java source compiles to a standard, platform-independent set of bytecodes, which interacts with a Java virtual machine (JVM). The JVM is a separate program optimized for the specific platform on which you execute your Java code. Figure 1-3 shows how Java can maintain platform independence. Your Java source is compiled into bytecodes, which are platform independent. Each platform has installed a JVM that is specific to its operating system. The Java bytecodes from your source get interpreted through the JVM into appropriate platform dependent actions.

Figure 1-3 Java Component Structure

When you develop a Java program, you use predefined core class libraries written in the Java language. The Java core class libraries are logically divided into packages that provide commonly-used functionality, such as basic language support (java.lang), input/output (java.io), and network access (java.net). Together, the JVM and core class libraries provide a platform on which Java programmers can develop with the confidence that any hardware and operating system that supports Java will execute their program. This concept is what drives the "write once, run anywhere" idea of Java.

Figure 1-4 illustrates how Oracle's Java applications sit on top of the Java core class libraries, which in turn sit on top of the JVM. Because Oracle's Java support system is located within the database, the JVM interacts with the Oracle database libraries, instead of directly with the operating system.

Figure 1-4 JServer Component Structure

Sun Microsystems furnishes publicly available specifications for both the Java language and the JVM. The Java language specification (JLS) defines things such as syntax and semantics; the JVM specification defines the necessary low-level behavior for the "machine" that executes the bytecodes. In addition, Sun Microsystems provides a compatibility test suite for JVM implementors to determine if they have complied with the specifications. This test suite is known as the Java Compatibility Kit (JCK). Oracle's JVM implementation complies fully with JCK. Part of the overall Java strategy is that an openly specified standard, together with a simple way to verify compliance with that standard, allows vendors to offer uniform support for Java across all platforms.

Key Features of the Java Language

The Java language has key features that make it ideal for developing server applications. These features include:

Simplicity--Java is a simpler language to master than most others you use in server applications because of its consistent enforcement of the object model. The large, standard set of class libraries brings powerful tools to Java developers on all platforms.

Portability--Java is portable across platforms. It is possible to write platform-dependent code in Java, but it is also simple to write programs that move seamlessly across machines. Oracle server applications, which do not support graphical user interfaces directly on the platform that hosts them, also tend to avoid the few platform portability issues that Java has.

Automatic Storage Management--The Java virtual machine automatically performs all memory allocation and deallocation during program execution. Java programmers can neither allocate nor free memory explicitly. Instead, they depend on the JVM to perform these bookkeeping operations, allocating memory as they create new objects and deallocating memory when the objects are no longer referenced. The latter operation is known as garbage collection.

Strong Typing--Before you use a Java variable, you must declare the class of the object it will hold. Java's strong typing makes it possible to provide a reasonable and safe solution to inter-language calls in the case of Java and PL/SQL and to integrate Java and SQL.

No Pointers--Although Java retains much of the flavor of C in its syntax, it does not support direct pointers or pointer manipulation. You pass all parameters, except primitive types, by reference (that is, object identity is preserved), not by value. Java does not provide C's low level, direct access to pointers, which eliminates memory corruption and leaks.

Exception Handling--Java exceptions are objects. Java requires developers to declare which exceptions can be thrown by methods in any particular class.

Flexible Namespace--Java defines classes and holds them within a hierarchical structure that mirrors the Internet's domain namespace. You can distribute Java applications and avoid name collisions. Java extensions such as the Java Naming and Directory Interface (JNDI) provide a framework for multiple name services to be federated. Java's namespace approach is flexible enough for Oracle to incorporate the concept of a schema for resolving class names, while fully complying with the language specification.

Security--The design of Java bytecodes and the JVM allow for built-in mechanisms to verify Java binary code has not been tampered with. Oracle8i is installed with an instance of SecurityManager, which, combined with Oracle database security, secures who can invoke any Java methods.