Java
Back Home Up Next

 

  Theory

Projects

Articles

 Written Books

Report

Technical Report

Survey Reports

Workshop

Presentations

Tutorials

Algorithms

Contact Me

Yourself

JAVA Learning

 

What is Java?

Before we can really answer that, we have to answer another question:

What is the Object-Oriented Paradigm?

The Object-Oriented Paradigm, or OOP, is a method of coding which results in better, more reliable and more reusable code.

"The fundamental idea behind object-oriented languages is to combine into a single unit both data and the functions that operate on that data. Such a unit is called an object." [LaFore, 1995] By using objects, we can model the real world in a more natural fashion, and we also achieve some other useful side effects.

An example of OOP v/s Structured programming:

Let's say we have to write code that will model a store. We have to keep track of customers, how much money the customers have, and how much the customers have bought. We have to keep track of the sales clerks, where they are and when their shifts are. And we have to keep track of the merchadise, how much we have and where it is.

First we'll look at a Structural method. To keep track of the customers and their money and purchases, we'll need an array of structures. Same for the clerks, and same for the merchandise. That pretty much takes care of the data.


Now, we'll need a function to spend a customer's money, one to add a customer's purchases, one to move the clerks, one to update the clerks' shifts, one to move merchandise, and one to sell the merchandise. Each of these functions will be globally available and will be called by a larger control structure. Also, all of the data will be visable to all of the functions.

Now, let's look at an OOP implementation. We'll define three objects, Customer, Clerk, and Merchandise. The Customer object will have a Money variable and a Purchases array. The Customer object will also have a Spend method and a Buy method to update the money and purchases, respectively.

The Clerk object will have a Location variable and Shift variable. It will have a Move method and a CheckShift method. The Merchandise object will have a Price variable and a Location variable. It will have Move and Sell methods. We will have to have three arrays, one for each object type. The methods will be visable to the control structure, but the data will be hidden, or encapsulated, within each object.

So, what's the difference? They both have pretty much the same stuff; it's just arranged a little differently. Well, the different arrangement is what makes OOP more powerful. The first obvious advantage is that the data is hidden. You cannot accidentally alter the data for a customer while fiddling with something else. You can only access one of the object's data by directly going through that object.

Another advantage is reusablilty of the code. Say, for instance, we now have to simulate an assembly line. One of the things we'll need to keep track of is where the workers are, and who's currently working. We can just borrow the Clerk object from our current model and plop it in our new project without any modification! It already knows how to keep track of where it is, and when it's shifts negin and end. That's all we need for an assembly-line worker.

Try doing that with the Structured code! You'd have to copy out the code for the structure, the code for each of the relevant functions, and modify the functions to fit the new array name, along with some other house keeping. OOP allows you to bundle together related data and functions so that they can be easily moved around and reused.

Yet another advantage is in maintenance. Say we want to be more specific now. We want to model a grocery store. And, we don't want to keep track of just "merchandise." We want to keep track of meat, fruits and vegatebles, and dry goods.


With the structured method, we'd have to trade the merchandise array for three separate item arrays. We would then have to write three new structures to handle the different data to be kept for each item. We would also have to modify all the functions which used the merchadise array to now work with the three new arrays, which could be a pain by itself!

With OOP we could take advantage of a property called inheritance. Inheritance allows an object to inherit code from another object, saving the time of writing all new code.
We could create three new objects, Meat, Fruit_N_Veggies and Dry_Goods. Each of these new objects can be a child of our previous Merchandise class. So, each will automatically inherit all of the data and function contained in Merchandise.

Then, we could further specifiy each new object. For example, for Meat, we could add a SellDate variable and a Spoiled method so that we can measure losses from spoilage.
Now, here's the really cool part. Since they are all children of Merchadise, they can all still go in the Merchandise array. We don't have to make a new array for each of them.

Now, the last real advantage we'll talk about is called polymorphism. The best way to explain this will be by example.

When we create a new Clerk, we want to be able to initialize his or her (Gender variable, anyone?) starting position and shifts. So, when we create a Clerk, we can do this:

Clerk new_clerk = new Clerk();

new_clerk.Location = "aisle 9";

new_clerk.Shift = "12pm-12am";

But, this is rather long-winded and clumbsy. We can define something called a constructor, which we'll discuss later, which will allow us to do the same thing like this:

Clerk new_clerk = new Clerk("aisle 9", "12pm-12am");

Now, isn't that better? But, the code for initializing the object is in the constructor, so we haven't really changed anything. Here is where the power of polymorphism comes in. What if we don't want to always assign both the shift and the location at the same time? What if we want to be able to just assign the location and leave the shift until later? We can do that without any problem. We can define another constructor so that we can do this:

Clerk new_clerk = new Clerk("aisle 9");

Now, look at the two initializations by constructor. they both call Clerk() (which is the name of the constructor). How can they both be named the same, but use different arguements? The answer is polymorphism! In OOP you can declare a method or constructor more than once, each with a different set of arguements, but the same name. When you call the method, the compiler knows from the arguement list, called the signature, which version of the method you mean.

This may not be a major code-saving feature, but it reduces confusion by 100%. Instead of add_int(), add_float(), add_short(), etc., you can just have an add() which will know by the arguements which one you need.

Well, now that we understand OOP, we can answer our original question:

What is Java?

Java is a "simple, object-oriented, distributed, interpreted, robust, secure, architecture neutral, portable, high-performance, multithreaded, and dynamic language." [Flanagan, 1996]

What does all that mean?

Simple: Java was made to look and act much like C and C++, since so many people are already familiar with those languages. However, to simplify matters, several features common to C and C++ were not included. Among those are pointers, header files, and goto's.

Object-Oriented: We just finished explaining that. Java is not 100% object-oriented like SmallTalk, but it is much more so that C++.

Distributed: Java was designed with today's distributed networks in mind. It is capable of network communication and handling socket calls.

Interpreted: Java code is compiled into byte-code, which is somewhat similar to a binary executable. Instead of being run by your operating system, though, the byte-code is run by the Java Virtual Machine, a byte-code interpreter. The advantage is that the Java code doesn't have to be directly translated into the system-specific machine code. Instead, the Java Virtual Machine acts as an intermediary which will be the same on every system. So, the end result is code that acts the same on every computer.

Robust: Java is a strongly typed language, and so will catch most errors long before run-time. Also, since Java doesn't support pointers, code written in Java is much more reliable. Another feature adding to Java's robustness is its exception handling. When an error occurs, the code is able to deal with it on the fly, allowing for a high rate of recovery.

Secure: Java was designed with the internet in mind. As such, it has to be secure to be usable at all. Java applets are not allowed to do any file I/O. Also, the lack of pointers prevents a large amount of potential problems.

The internet is a dangerous place. There is really no way to be competely secure without being useless. Java has tried to find a middle ground between being unprotected and being unusable.

Portable: Because Java runs on the Java Virtual Machine, and not the individual system itself, Java code is easily portable to any system capable of running the virtual machine.

Performance: Java is approxiamtely 20 times slower than C. However, it is more than fast enough for most of its more commons uses such as applets and multimedia. Java does allow you, though, to import native C code for the times when speed is essential.

Multithreaded: Java can run several simulateous process threads. This allows the user to easily code programs with can do more than one thing at once. Such multitasking capability is invaluable for use in building GUI's and other such applications.

Dynamic: Java was built to be able to adapt to the continually evolving environment. It can dynamically load in classes when they are needed, and it can even got out over the 'Net to find them.

 

References:
[LaFore, 1995] Robert LaFore, "Object-Oriented Programming in C++," The Waite Group Press, 1995, p.6.
[Flanagan, 1996] David Flanagan, "Java in a Nutshell," O'Reilly & Associates, Inc., 1996, p.xii.

Welcome to Using Classes

We've already talked a little about objects, and you should have some idea what an object is. Well, classes are were objects come from. A class is to an object, as a data type is to a variable. (And you thought you didn't need English to program!) In geek speak that is, "An object is an instantiation of a class."

O.K., so you don't remember what an object is really. Let's go back over them briefly. Objects are the basic building block of an object-oriented program. Each object contains some data and the functions (called methods) which act on that data. For instance, say we have an object that is a stack. It will have an array to store the data in and push() and pop() methods for accessing the array. The power of objects comes from the fact that the data array can only be accessed through push() and pop().
The Stack class is the code that is used to instantiate the stack object. Here's a brief example:

public class Stack { private int[] data_array; private int current=0; public int pop () { if (current != 0) return(data_array[current--]); else return(-1); } public void push (int data) { data_array[++current] = data; } } public class Test { public Stack my_stack; public void PushNPop () { int value; my_stack.push(5); my_stack.push(10); value = my_stack.pop(); } } I have left out a couple of details, such as initializing the data_array, but that's not important right now.

What I have done is create a Stack class. It has an array for data, a variable to keep track of what the top of the stack is, and push() and pop() methods. Notice that the pop() method will return -1 if the stack is empty.
I then created another class called Test which uses a stack object called my_stack. It has a PushNPop() method which pushes and pop the stack.

Let's look a little more closely. First of all, what do all the public and privates mean? Public means anyone can see the variable or use the method or instantiate the class. Private means only methods within the class can use the variable or use the method. Very seldom will you see a private class.

In the Stack class, data_array and current are private. That means only the push() and pop() methods can use them. So, the only way you can access the contents of the stack is through those methods. The methods themselves are public, meaning anyone can use them, just as Test does.

Second, notice how PushNPop() called the push() and pop() methods. When you call a methods, you must specify which object's methods you're calling. That is done with the "." operator. So, my_stack.pop() says to call the pop() method of the object my_stack. Notice also that pop() does return a value. Why is it worth doing all that work for just a stack? Well, look at it this way: When PushNPop() calls pop(), does it have to worry about whether the stack is empty or not? Does PushNPop() even know how the stack is stored? No. We could completely reformat the Stack class, and so long as it still has a pop() method that returns an interger, PushNPop() will never know the difference.

For another advantage, let's look at another piece of code:

public class Test2 { public Stack stack1,stack2; public PushNPop () { stack1.push(1); stack1.push(5); stack2.push(stack1.pop()); stack2.push(stack1.pop()); } } Now we're handling two separate stacks. PushNPop() pushes two numbers onto stack1 and then pops them off and pushes them onto stack2. Try doing that as easily without the use of objects!

Here we also see why we must use the "." when calling a method. Because we can have more than one object of the same class, we must specify which object's method we're calling.

By the way, in case you're wondering, after executing PushNPop(), stack1 will contain nothing, and stack2 will contain {5,1}. (From this point onward, I will assume you're sold on the idea of objects. I'll concentrate instead on selling you on Java.)

One of the great things about Java is it's huge class library. Java has a very large library of predefined classes that you can use. For instance, our Stack class is not necessary since it is already defined in Java's class library.

A very important class in the Java class library is the Applet class. You've seen a little of the Applet class in the previous lesson. The Applet class is the class from which all applets are derived. Every applet must inherit from java.applet.Applet somewhere along the line. Inheritance is a way for a class to gain all of the properties and abilities of another class. In Java, the extends keyword is used to declare inheritance for a class. The Applet class has the ability to interface with Netscape and other browsers.

The Applet class has four important methods: init(), start(), paint(), and stop(). These four methods are the ones called by Netscape when it wants to run the applet. The first time it tries to run the applet, Netscape will call the init() method. The init() method is used to do variable initializations and other things that need to be done before the applet runs, and that only need to be done once. Next, Netscape calls start(). The start() method is the once that gets things going.

It starts the applet doing whatever it does. When Netscape needs the applet to display itself, it calls the paint() method. The paint() methods should draw everything on the screen that needs to be drawn. Finally, when the user goes to another page, Netscape calls the stop() method. stop() should kill all of the applet's active processes and generally gets things cleaned up and ready to quit. Let's look at some examples.

import java.applet.*; import java.awt.*; public class HelloWorldApplet extends Applet { public void paint(Graphics g) { g.drawString("Hello World", 25, 50); } }

This is the same example we saw earlier. First, you see that this HelloWorldApplet extends Applet. By inheriting from Applet, HelloWorldApplet gains the ability to interface with web browsers.

Second, notice that this class only has a paint() method. Where are the other methods like init() and start()? Well, the answer has to do with inheritance. Since HelloWorldApplet is a child of Applet, it inherits all of Applet's non-private variables and methods. So, HelloWorldApplet has the same init(), paint(), start(), etc. as Applet. Then why does HelloWorldApplet define a paint() method if it already has one it inherited from Applet? Well, the paint() method inherited from Applet is a generic paint() method that really doesn't do anything. So, HelloWorldApplet has to override Applet's paint() method with its own. That way, HelloWorldApplet has a paint() method which does specifically what it needs. Any time a class redefines one of it's parent's methods or vartiables, it's called overriding.

import java.applet.*; import java.awt.*; public class HelloWorldApplet2 extends Applet { private String print_string; public void init() { print_string = "Hello World"; } public void paint(Graphics g) { g.drawString(print_string, 25, 50); } }

Now we changed things a little. We've added a private variable and an init() method. Why? No reason really. I just wanted to make the example a little more complex. Let's look at the differences between the last class and this one.
First, the patin() method has changed a little. Instead of passing it a string of text, we're now passing it a variable. The variable print_string is declared outside of the methods of the class, so it is "global" within the class. That means that any method in the class can use it and/or change it's value. (Java claims to not allow any global variables, which is true, but I can't think of a better word to use.) So, now that w

Welcome to Advanced Classes

In the last two lessons we've talked several times about inheritance, but we've never really fully explained how it works. We're going to do that now before we go any further. Also, we'll explore constructors, the finalize() method, static and constant variables, and we'll revisit our HelloWorldApplet.

Let's pretend we have a class called Person. Person has methods such as walk(), talk(), breathe() (a private method), and eatAndDrink(), and variables such as height, weight, eye_color, and hair_color. Now, you'll notice that our Person class is very general. It has only the most basic elements. It does not even have gender.

O.K. We definitely need Male and Female classes. So, we'll inherit Male from Person. Males don't really do much of anything special, so we don't need to add any variables or methods. Now, to remain biblically correct, we'll inherit Female from Male. Now Female needs a new method, haveBaby(). The haveBaby() method will return a Baby object, so we need to define a Baby class. Baby will inherit from person since a baby isn't really a man or a woman. Baby will need a new method, cry(), and a new boolean variable, diapers_dirty. (A boolean variable is true or false.) The Baby class will also have to have new eatAndDrink() and walk() methods since babies don't do that quite the same as adults. What we'll have to do is override the eatAndDrink() and walk() methods from Person by declaring an eatAndDrink() method and a walk() method in Baby.

Alright, so what we have is a Male class with walk(), talk(), breathe(), eatAndDrink(), height, weight, eye_color, and hair_color. We also have a Female class with walk(), talk(), breathe(), eatAndDrink(), haveBaby(), height, weight, eye_color, and hair_color. And we have a Baby class with walk(), talk(), breathe(), eatAndDrink(), cry(), height, weight, eye_color, hair_color, and diapers_dirty. We also still have our original Person class. The pseudo-code follows. I have left the methods empty since the internals are not important right now.

import java.awt.Color; public class Person { protected float height; protected float wieght; protected Color eye_color; protected Color hair_color; public void walk() {} public void talk() {} public void breathe() {} public void eatAndDrink() {} } public class Male extends Person { } public class Female extends Person { private Baby haveBaby() {} } public class Baby extends Person { public boolean diapers_dirty; public void cry() {} public void eatAndDrink() {} public void walk() {} }

We now can declare a whole family! But, there's more to life than family. We can't forget work. So, let's define some working classes. Let's start with Actress. Actress should inherit from Female. Actress will need an act() method and a salary variable. Let's also define a Salesman. Salesman will inherit from Male, and will need a sell() method, a salary variable, and a stock variable. Let's also define a Mother class. Mother will inherit from Female. All mother needs is a Baby. Here's the code:

public class Actress { protected int salary; public void act(); } public class Salesman { protected int salary; private Vector stock; public void sell(); } public class Mother { protected Baby junior; }

Now that's more like it! The Vector object in Salesman is from the Java library. It provides an easy way to keep track of several of objects at once.
Our Actress class can act(), haveBaby(), eatAndDrink(), walk(), talk() and breathe(). It has a salary, height, wieght, eye_color, and hair_color. The Salesman and Mother class work similarly.

Now for the part that makes inheritance really powerful. Mother is a Female is a Person. If we need to, we can treat any object as one of it's parents. For example, if our Male class had a marry() method which took a Female as a parameter, we could pass it an Actress because Actress can act as a Female. To clarify, let's look at some pseudo-code.

public class Man extends Male { private Female wife; public void marry (Female woman) { wife = woman; } public void divorce () { wife = null; } } Man george = new Man (); Female gisela = new Female (); Actress zelda = new Actress (); george.marry (gisela); george.divorce (); george.marry (zelda);

Here you can see that the marry() method which expects a Female will accept either a Female or an Actress. It would also accept a Mother. The marry() method will accept any Female or any class inherited from Female. If we inherited a new class, AerobicsInstructor, from Actress, marry() would also accept that. The point I'm trying to make here is that marry() will accept any object that is somehow a decendant of Female.

This property, called polymorphism, allows you to do some really neato stuff. You could, for instance, declare an array of Persons. In that array, you could put, Males, Females, Salesmans, and AerobicInstructors because they are all descendants of Person. We may see more of this in later lessons.

One other thing polymorphism allows you to do is to call a method from the parent, even if it has been overridden. For example:

public class Baby extends Person { public boolean diapers_dirty; public void cry() {} public void eatAndDrink() {} public void walk() {} public void adultEatAndDrink() { super.eatAndDrink(); } public void adultWalk() { super.walk(); } }

We just redefined our Baby class to add a little surprise for Mommy and Daddy. We added two methods, adultEatAndDrink() and adultWalk(). Both methods just call a method of the parent class by using the super keyword. Here's what this will do: When adultWalk() is called in a Baby, it calls the walk() method of Baby's parent, Person. The walk() method of Person is the way adults walk. So, what will happen is that Baby will get up off his hands and knees and start strutting like Travolta. Or something to that effect. adultEatAndDrink() will have a similar effect. It will call Parent's eatAndDrink() method, and Baby will be downing cheeseburgers and coffee.

In Java, a class can only inherit from one other class. There is no mulitple inheritance as C++ programmers are used to. Instead, Java offers something called interfaces. A class can implement any number of interfaces. An interface is like a skeletal class. It can only contain methods, no variables, and its methods must be abstract. Abstract methods contain no code. They simply state that the method exists. So, in effect, an interface is kind of like a set of parameters for a class to follow. It states what methods the class needs to implement. Again, polymorphism applies to interfaces. I know that didn't make much sense, so let's look at some more code. This time, we're going to come up with a more sensible way of defining working classes.

public interface Law { public abstract void doLawyerStuff (); public abstract void chargeHugeFee(); } public class MaleLawyer extends Male implements Law { public int number_of_cases_won; public void doLawyerStuff () {} public void chargeHugeFee() {} } public class FemaleLawyer extends Female implements Law { public void doLawyerStuff () {} public void chargeHugeFee() {} }

What we have now is an interface called Law. Any class that implements Law is required to have everything needed to be a lawyer, doLawyerStuff() and chargeHugeFee(). We also defined two kinds of lawyers, MaleLawyer and FemaleLawyer. Both define the above two methods. MaleLawyer also adds a variable to keep track of the number of wins so he can boast to his buddies.

The FemaleLawyer class is a Female and a Person, and quailifies at Law. So, FemaleLawyer can act as a Person, a Female, or a Law. I know that sounds a little odd, but it works. We can declare an array of type Law, and we can put FemaleLawyers and MaleLawyers in it. We cannot, however, put Laws in it since they don't really exist; Law is an interface, not a class. Again, we will see more of this in later examples.

Let's now look at another part of the mechanics of a class, constructors. Constructors are used to create an instance of a class. For instance, when we declared george as a Man a little while back, we used a constructor for class Man. However, since we hadn't declared any constructors for Man, we ended up using the default constructor. Anytime there are no constructors defined, a default constructor is included by the compiler. Let's start with an example.

public class Man extends Male { private Female wife; public Man () { wife = null; } public void marry (Female woman) { wife = woman; } public void divorce () { wife = null; } }

Now we've extended our Man class to contain a constructor. Constructors are always named after the class, and never declare a return value, as you can see above. What this constructor does is set the wife variable to null when a Man is created, meaning that he has no wife.

What if we wanted to allow a Man to already be married when he is created? We can take advantage of another application of polymorphism. Methods can be polymorphic too. What that means is that two methods can have the same name, as long they have different parameters.

public class Man extends Male { private Female wife; public Man () { wife = null; } public Man (Female woman) { wife = woman; } public void marry (Female woman) { wife = woman; } public void divorce () { wife = null; } }

We can now create a Man with or without a wife. Notice that both constructors have the name Man, but on tkaes no parameters, and the other takes a Female as a parameter. Here's how we would use this class.

Man george = new Man (); Female gisela = new Female (); Man frank = new Man (gisela); Actress zelda = new Actress (); frank.divorce(); frank.marry(zelda); george.marry(gisela);

Love is so complicated! Notice that Frank was created with a wife, Gisela, whom he later divorces, and George was created without a wife but later marries the recently divorced Gisela. To be perfectly PC, and include alternative lifestyles, we could redefine Man as follows, using the polymorphics property:

public class NewMan extends Male { private Person partner; public Man () { partner = null; } public void marry (Female woman) { partner = woman; } public void marry (Male man) { partner = man; } public void divorce () { partner = null; } } NewMan fred = new NewMan (); Actress zelda = new Actress (); MaleLawyer bob = new MaleLawyer (); fred.marry (zelda); fred.divorce; fred.marry (bob);

There are many different levels of polymorphism at work here. First, wife is now a person, so it can accept anything inherited from Person, including Actress and MaleLawyer. There are now two marry () methods. One accepts a Female, and the other a Male. There is no difference in the way they are called. The difference is in what kind of object you pass it. If you pass a Female, it knows to use the first marry() method. If you pass a Male, it knows to use the second marry() method. If you try to pass a Baby, you will get an error, because there is no marry() method which expects a Baby or just a Person. Besides, that's illegal!

Now, one more thing about constructors. A constructor in a child class can call the constructor of its parent class. In fact, it does this automatically, whether you want it to or not. But, it is always better to explicitly declare, just so that nothing is going on behind the scenes. To call the parent's constructor, use the super() method. The call to super() has to be the first statement in the constructor. Let's see another example.

public class Father extends Man { protected Baby junior; public Father () { super (); } public Father (Female woman) { super (woman); } public Father (Female woman, Baby kid) { super (woman); junior = kid; } }

What we have created is a father class. We can create our Father with no wife, with a wife, or with a wife and a child. Notice that we use the wife variable from Man, so we don't have to declare one in Father. We also take advantage of the constructors in Man. The first one in Father, the empty constructor, would be supplied by the compiler anyway, but it's always a good idea to declare it explicitly.

On the other side of constructors is the finalize() method. The finalize() method is used to clean things up before an object is destroyed. Proper use of this method can result in faster clean up time and better performance. However, for most basic application, it's not necessary.

public class Man extends Male { private Female wife; public Man () { wife = null; } public void finalize () { wife = null; } public void marry (Female woman) { wife = woman; } public void divorce () { wife = null; } }

Here we've added a finalize() method. The finalize() method always has a return value of void, and takes no parameters. This finalize() method just assigns null to the wife variable so that the automatic garbage clean up will get to it faster. You can only have one finalize method per class. We will be seeing much more of constructors and a little more of the finalize() method in the following lessons.

Alright, let's talk a little about variables. There are many modifiers we can add to a variable declaration to make subtle changes to the way the variable works. Right now we're going to look at two of them, static and final.

Final makes the variable a constant. After it is declared, the variable can no longer be modified. It's very similar to the const statement in C++.

Static does something a little odd with the variable it modifies. It makes it into a "class variable." Class variables exists whether there are any instances of the class or not. Only variables declared outside of the classes methods can be declared static.

Let's look at an example.

public class Test { public static int var1 = 0; public final int var2 = 2; public static final int var3 = 3; public Test () { var1++; } } In this example, var1 keeps track of the number of Test objects that have been instantiated. Since it is static, var1 is a class variable. There is only one var1, no matter how many Test objects get instantiated. And every Test object will have the same var1. In this example, the constructor for the Test class increments var1. So, every time a Test object is created, var1 is incremented. This means that var1 always holds the number of Test objects that have been created. Also, var1 can be accessed by any object as Test.var1.


var2 is a constant equal to 2. It will always equal 2, and it cannot be changed. Because it is public, it can be accessed by other objects, but a Test object has to be instantiated, and var2 must be referenced through it. For instance, it we had a Test object called test_object, we could access it's var2 with test_object.var2. Note, however, that it is accessible by other objects only because it is public. If var2 were private, only methods within Test could access it. var3 is a constant equal to 3. It can be accessed by any object as Test.var3, but it cannot be changed by any object. It is rather a cross between var1 and var2.

Methods can also be declared final and static. A final method cannot be overriden in a subclass. A static method acts rather like a static variable. It is a class method, and can be called even if no objects have been instantiated from the class.

A good example of a static final variable is Math.PI. It is declared in java.lang.Math, but it's usable from anywhere without instantiating a Math object.
A good exmaple of a static method is Math.sqrt(). It is also declared in java.lang.Math. You can always call it, even if no Math objects exist.

Now, on a completely different note, let's go back and look at our HelloWorldApplet again.

The thing everyone wants to do with Java is to add pictures, sound, and animation. In the remainder of this lesson, we'll cover sound and pictures. Animation will come later.

First I'll show you the code to add an image to an applet, then I'll explain it.

import java.applet.*; import java.awt.*; public class HelloWorldApplet6 extends Applet { private Image coffee; public void start () { coffee = this.getImage (this.getDocumentBase (),"javaback.gif"); } public void paint (Graphics g) { g.fillRect (0,0,57,62); g.drawImage (coffee,2,2,this); g.drawString ("Hello", 15, 25); g.drawString ("World", 12, 45); } }

First, this HelloWorldApplet draws a filled rectangle that is slightly larger than the image we're going to use. The effect is that the rectangle becomes a frame for the image. I did that just to make the image stand out against the background.


Next, it loads a copy of the image and stores it in a variable called coffee. It does so by using a method of the Applet class, getImage(). It is called as this.getImage() to specify that the applet is calling the method. getImage() takes two parameters, a URL where the image is located, and the name of the image. Since the image is in the same directory as the applet, we can use the URL of the applet. We get the URL of the applet by using getDocumentBase(), again called with the this keyowrd. getDocumentBase returns the URL of the applet it's called from.


Next, we draw the image on the screen. drawImage is a method of Graphics we haven't seen before. It simply draws the indicated image on the screen with the upper left corner at the specified coordinates, (2,2) in this case. The last parameter that we passed this is one of the really advanced topics, and we probably won't cover that in this tutorial. Just take it as given that you have to pass this as the forth parameter of drawImage().
Finally, we print "Hello World" on the screen. We had to break it up because the image was too small.

We put the image load in the start() because it only needs to be done once every time you view the page. The paint() method gets called several times while you look at a page. In general, you only want things necessary for redrawing the applet to be in the paint() method. That's all there is to it. You can draw any number of images in this way. Just be sure to import java.awt.*, because that's where the Image class is located.

Sound works in a very similar way.

import java.applet.*; import java.awt.*; public class HelloWorldApplet7 extends Applet { private Image coffee; public void start () { this.play (this.getDocumentBase (), "c_welcome.au"); coffee = this.getImage (this.getDocumentBase (),"javaback.gif"); } public void paint (Graphics g) { g.fillRect (0,0,57,62); g.drawImage (coffee,2,2,this); g.drawString ("Hello", 15, 25); g.drawString ("World", 12, 45); } }

The only real difference between loading an image and loading a sound is that the sound plays immediately; you don't have to display it or tell it to play.

Again we've put the sound in the start() method. This means that the soud will only be played when the page is reloaded, which is a much better alternantive than putting it in paint() and having called several times in rapid succession.