Furthermore, not only is the source code portable between machines it is not even necessary to recompile the code! When one compiles the code (using under unix the command javac myfile.java) an output file called a byte code is produced. This is intermediate between source and a true binary code. To run the code it must be fed into the Java intepreter which translates the byte code into binary machine instructions 'on-the-fly' at runtime. The byte code can be transferred to any other machine with a Java interpreter and run directly.
In the context of the Web it is possible for a browser containing the Java interpreter (such as Netscape 3.0) to download a byte code on the server to the local machine, run it without any recompilation, and display the results directly in the Web page. In this context Java programs are called applets.
Fruit and inside this
variable we can package the two pieces of data relevant to
our ideal fruit object. It does this by defining a class
Fruit
with the code
class Fruit{
int grams;
int cals_per_gram;
}
Notice that 'up-close' the syntax is like C. OOP (and Java) goes further than
this - it allows us to include functions that operate directly on this
Fruit data within the class definition.
Thus we could enlarge the Fruit
class by adding a function to compute the total calories possessed by
that piece of fruit
class Fruit{
int grams;
int cals_per_gram;
int total_calories()
{
return(grams*cals_per_gram);
}
}
Not only does Java allow us to define functions
inside objects - it forces us to do so ! - all functions belong to
one object or another. This is an attempt to keep data and the functions
that act on it in one place. Functions are called methods in Java.
To create such a Fruit object we use the code fragment
Fruit plum = new Fruit();This defines plum to be an object of type
Fruit and
creates space for
it (and its data and method fields) in memory - this being achieved with
the special new operator. Notice the righthand side of this
assignment contains the Fruit() function (or method). This is a special
constructor method which is used to initialize this instance
of the Fruit class. Every class must contain such a constructor. We
must correct our definition of Fruit to contain such a method
class Fruit{
int grams;
int cals_per_gram;
Fruit(){grams=50;cals_per_gram=0;}
int total_calories(){
return(grams*cals_per_gram);
}
}
So we have learnt how to define an object or class in Java and how to
create it. Now we must learn how to use it. An example should suffice.
Suppose we create an object of Fruit type and want to compute its
total_calories. We might do this with the lines
// double forward slashes mark comments in Java // need some more lines before here Fruit plum = new Fruit(); int cals = plum.total_calories();Note that the
. operator allows you to access the'
method total_calories() inside the plum instance of
Fruit.
One of the most important features of OOP languages (and Java
in particular) is the concept of inheritance. This means that
a new class can be based on existing classes. For example we might want
to define a new 'specialized' type of fruit class called Citrus. A
Citrus object has all the previous data and methods of Fruit
but may have
its own unique methods in addition. For example, it might have
some method squeeze(). Instead of retyping the code
associated with the methods and data in Fruit we can
inherit them automatically in Citrus. In Java
the keyword extend does this. The class definition of
Citrus is given below.
class Citrus extends Fruit{
void squeeze(){plug some code in here}
}
Here is an example of how to use this new class
Citrus lemon = new Citrus(); lemon.squeeze(); \\ the new method lemon.total_calories(); \\ we have access to all the old Fruit methods also
One of the features of OOP is called overloading. This refers to
use of several methods with the same name within a class definition.
For example, we have discussed a constructor method for Fruit
which
assigns default numbers for the data grams and
cals_per_gram. AS an alternative it would be nice to be able to
assign these numbers differently when we create new instances of
Fruit. Java allows us to do this; inside the Fruit
class definition, add another definition for the Fruit constructor which
takes two arguments
Fruit();
Fruit(a,b){
grams=a;
cals_per_gram=b;}
Thus both of the following code fragments are legitimatel
plum = new Fruit(); grape = new Fruit(5,10);
By looking at the number and type of arguments the Java compiler is
able to figure out which version of the method you want. This idea
of making related but different methods have the same name can
be applied in another, much more powerful context- so called
method overriding. Suppose we were to add a method peel()
to the class Fruit. Since Citrus
extends Fruit it will inherit this version of the peel method also.
So I can say
// ... lemon.peel();Th new feature called overriding is the ability to redefine the
peel() method within the Citrus class so
that it does something specific to Citrus fruits. Then when the
peel() method is invoked on a Citrus object
it uses not the general Fruit
version but the Citrus version. The process
of determining which version of peel to use
is done at runtime by the
Java interpreter.
class MySimulationApplet extends java.applet.Applet{
// code goes here
}
The applets constructed for this course are built out a set of simple objects or classes. First there is an object that inherits from Applet as above. This applet contains code to start and stop the applet and to create all the other objects needed by the program.
Next there are two objects called, for example, DrawSim and Controls that contain code for plotting to the screen and handling the user interface - the buttons, scrollbars and check boxes that are typically displayed.
Finally there is an object called Simulation that contains the code for the simulation. You will see that the source code (which lives in the file Simulation.java) for this starts with the line
public class Simulation implements Runnable{
The keyword implements is rather like extends and
implies that the class will contain a method called run()
which will contain the code that would have lived in main
if this were a C program. In fact these applets were constructed by
pasting in the appropriate C code, renaming main to run
and declaring all other C functions to be private methods
of Simulation. The keyword private tells the
compiler that this method or data cannot be accessed outside of that
class - as opposed to public data.
The only other thing one needs to know to understand the code inside
Simulation is how arrays are handled. The C arrays must
be modified to be used in Java. Specifically they must be created
with the code fragment double x[] = new double[100]
for example. For this course it will not be necessary to
understand the contents of the DrawSim and Controls
classes.
Additional information on Java and applets can be found at Sun's site on the Web (www.javasoft.com)