9:00
About Java The Language OOJ Code Classes Keywords |
10:00
Types Variables Operations Class Decls. Interfaces Packages |
11:00
Gnomes Threads Synchronization Exceptions |
12:00
Lunch Break |
1:00
Environment |
2:00 | 3:00 | 4:00 |
Does Java make you think of coffee? Coffee is indeed a major export, along with tea, tobacco, sugar, coconuts, and cinchona. But the main food crop is rice, along with corn, soybeans, peanuts, sweet potatoes, and cassava.
Do you equate Java with a cup of coffee? Time to wake up and smell the real Java!
If the next popular programming language is called "England", we'll
work to educate you about that island as well, even though England is relatively
boring, having far fewer people, square miles, and volcanos than Java.
Java programs are just sets of classes.
A Java Applet is a program that is referenced by a web page, and run by a Java interpreter in your browser when you browse that page.
Any time a class is needed, the browser will load the .class file (probably over the internet) just once (then it is cached), after which point it can make instances of the class as often as it likes.
An applet is not the main program -- it just responds to various UI (user interface) events, like the page being loaded by the browser, or a mouse click. Various routines are called when various events happen, so there are typically many "points of entry" into an applet.
JavaScript is a completely separate language, originally named LiveScript, but renamed to JavaScript by its creator, Netscape, somewhat early on. You can include JavaScript source code in an HTML document. We will not discuss JavaScript here. JavaServer Pages (.jsp) are a way of embedding Java code into HTML-ish pages. We will not discuss JavaServer Pages here either, although probably we should. [Thanks to Jeff Medina for this info.]
A class is a collection of methods, and a collection of variables.
Like a struct in C, or a record in Pascal, the variables exist as a group for every instance of the class.
Each occurrence of the struct/record (each region of memory which contains
a set of the variables) is called an object.
Wait, didn't we just say it's called an instance? Yes, an object
is an instance of its class.
To know the class of the object is to know what struct/record/(set of
variables) it has, and what methods it can perform.
What, how can a set of variables perform anything? Ah, this is
the crux of object-oriented thought. All code is thought of as being
executed by some object or another.
Here is some simple Java code:
class Point { // we are defining a class called "Point"Every method in a class has a secret unlisted argument, called this, which is the group of variables. For example, the above function translate somehow has to know which point it is translating. The caller must tell it which point to translate. Any call to translate must be with regard to a specific instance of the Point class.
int x, y, z; // it has three integer instance variables
// (every Point instance will have its
// own values for these variables)// here is a 3-argument function "translate"
void translate(int dx, int dy, int dz) {
x += dx; // this function adds (dx,dy,dz) to (x,y,z)
y += dy;
this.z += dz; // "this.z" is exactly the same as "z"
}
}
Point p1; // this says the variable p1 can hold a PointThe last line indicates that when translate is called, the implicit argument this will be equal to p1.
// but it doesn't hold anything yet (it is null)
p1 = new Point(); // this assigns a newly created point to p1
p1.x = 3;
p1.y = p1.x + 5; // we can work with instance variables like this
p1.z = -4;
p1.translate(2,2,2); // we can invoke the translate method on p1
translate(0,3,0);is the same as:
this.translate(0,3,0);Of course, this only makes sense (is compilable) if this is a Point.
A subclass automatically inherits all the variables and methods of its superclass. It may also define new variables and methods. If it wishes, it can override (redefine) some of the inherited methods.
Here we define a subclass of Point. We say that we are subclassing Point:
class ColoredPoint extends Point {Then we could have code like:
int colorNumber;
void changeColor() {
colorNumber++;
}
}
ColoredPoint cp;
cp = new ColoredPoint();
cp.x = 4;
cp.y = 5;
cp.z = 6;
cp.colorNumber = 3;
cp.translate(3,0,0);
cp.changeColor();
Some object oriented languages, like C++, allow multiple inheritance, meaning that a class can have more than one superclass. Other languages, like Objective C and, in particular, Java, do not allow multiple inheritance, so we will not discuss it any further!
Java's solution to the problem is the Interface.
An interface is like a class, except that it has no variables. It
just has a list of methods, and the methods don't even have any code!
An interface doesn't have any instances. So what good is it?
A class can be declared to implement an interface:
class Chair extends Furniture implements ComfortablePlace {Here is what the definition of the ComfortablePlace interface might look like:
boolean hasArmrests;
boolean canSwivel;
int legs;
boolean occupied;
boolean occupy() { // return whether occupation attempt succeeds
if (occupied)
return false;
occupied = true;
return true;
}
boolean leave() { // return whether attempt to leave succeeds
occupied = false;
return true;
}
}
interface ComfortablePlace {The compiler, upon seeing that class Chair is declared to implement the ComfortablePlace interface, will check that this is indeed so.
boolean occupy(); // return whether attempt succeeds
boolean leave(); // return whether attempt succeeds
}
Now, just as we declared the variable cp above to be of type ColoredPoint, we can declare a variable to be of type ComfortablePlace. Then the variable is allowed to hold any object that is of a class implementing ComfortablePlace, and we can invoke any method from the ComfortablePlace interface:
ComfortablePlace cp;In this way, a Chair is both a kind of Furniture and a kind of ComfortablePlace.
cp = new Chair();
cp.occupy();
Code is written in .java source files (typically one file per class, with the same name as the class), and compiled into .class class files.
For example, here is a "hello world" program, written as a file HelloWorld.java:
These are like #include statements
in C, specifying what libraries (or, more generally, what other classes)
will be used.
They must appear before any class
definitions.
import java.applet.Applet;
import java.awt.Graphics;
This says we will define a class
called HelloWorld, as a subclass of the already-defined class Applet
public class HelloWorld extends Applet {
Instance variables would go here
(or even class variables, indicated with "static"), but we don't happen
to have any.
Here we define a method called
paint, taking an argument g of type Graphics (that's why we included java.awt.Graphics
above)
public void paint(Graphics
g) {
The body of the method is just
to call g's drawString method (defined in java.awt.Graphics) with
some simple arguments
g.drawString("Hello
world!", 100, 30);
(0,0) is the upper left corner.
That starts drawing the string at (100,30).
}
}
To use this applet in a web page, we would use the following html:
<APPLET CODE="HelloWorld.class" WIDTH=200 HEIGHT=30>If this
here html is rendered then your browser can't run applets, perhaps because
an option to enable java is not selected.</APPLET>
This tells the browser that the file "HelloWorld.class" contains a class HelloWorld which must be a subclass of Applet so that it can respond to all the messages that the browser will send it. (Applet is in turn a subclass of Panel, then Container, then Component, which can draw and get events.) We have overridden only the paint method.
If you write a Java standalone program (instead of an Applet), then
you will use main(), like in C.
But that's a silly thing to do with Java -- the only real reason to
write in Java is to write platform-independent applets for people to run
in their browsers. And for applets, you do not need a main().
Instead, your Applet subclass (specified in the html) will be sent messages
such as start(), stop(), paint(), etc. These will be discussed at
1:00.
Here is a list of keywords to whet your appetite...
If y is another integer variable, you can't have x hold y. x can only hold an integer value, such as the value of y. An assignment statement like x=y says that x's value should become what y's value is.
Some people call variables "lvalues", where the "L" at the front of "lvalue" means that it is something that can appear on the Left hand side of an assignment. Whether you find this confusing or clarifying is up to you.
"Automatic" variables are those that are part of some code to execute. This name comes from how their storage space (on the stack) is automatically created and deleted when the routine is entered and exited. The only other kind of variable (besides automatic) in Java is an instance (or class) variable. These terms have to do with scope, not with type.
type description ------ ------------------------------------- byte 8 bit signed integer short 16 bit signed integer int 32 bit signed integer long 64 bit signed integer float 32 bit signed floating point number double 64 bit signed floating point number char 16 bit unsigned unicode boolean one of the two literal values: true or false (not a number) [name of class or interface] any object which is a kind of that class or interface [array type] any object which is a kind of thatThe first eight types listed above (i.e. all but the last two) are called the primitive types, since they are not defined in terms of anything else -- they are just sequences of bits that computer cpus are ready to deal with. You are probably already familiar with types like these, so I won't waste any more words trying to explain them!
Anything that is not a primitive type is a reference type.
A reference type is a class, interface, or array type.
A variable of any reference type may be set to null,
meaning that it doesn't hold anything.
(If you are familiar with pointers you will recognize that reference
types are pointers to objects.)
The last two types in the table mean that you can use a class or interface name just like you would use a primitive type. This is pretty neat. Every class is effectively a type. So if myDog is a variable of type Dog, then any kind of Dog may be assigned to the variable myDog. As another example, if a variable is of type Object, you can assign any object at all to it.
Dog bigDog = new Dog();
bigDog.fetch();
// This calls the fetch() routine defined in class Dog
Object anObject = bigDog; // This assignment
is ok, since Dog is a kind of Object
anObject.fetch();
// This is a compile-time error, since fetch() is
// not defined for Objects
((Dog)anObject).fetch(); // This
will work, but if anObject does not contain a
// kind of Dog when this statement is executed at
// run-time, then this will generate a ClassCastException
Even classes themselves are objects, of the class Class, so their type is Class. You don't normally have to deal with this, but it is reassuring to know that absolutely everything beyond the primitive types is an object of some class!
There are heaps of "built-in" classes (in the standard libraries), plus
of course all the classes you create.
So there are as many types as you want!
int[][] mat;
// mat === null (mat, as an object, defaults to null)
mat = new int[2][2]; // mat === {{0,0},
{0,0}}
mat = new int[3][]; // mat ===
{null, null, null}
mat[0] = new int[4]; // mat === {{0,0,0,0},
null, null}
mat[1] = new int[3]; // mat === {{0,0,0,0},
{0,0,0}, null}
mat[2] = new int[2]; // mat === {{0,0,0,0},
{0,0,0}, {0,0}}
mat[0][2] = 7;
// mat === {{0,0,7,0}, {0,0,0}, {0,0}}
mat[3][2] = 4;
// throws IndexOutOfBoundsException
If you have an array of type Dog[], then each member of the array can be any kind of Dog.
Dog[] dogList = new Dog[5]; // dogList holds {null, null, null, null, null}
new Dog[5] creates space to hold 5 dogs -- it creates 5 variables of type Dog. These variables are each initialized to null until you assign something else to them.
The source code can contain an explicitly typed-out array, but for some reason only in an initializer:
int[][] mat = {{2,3},{4,5}}; //
this is ok
mat = {{6,7},{8,9}};
// but this won't compile!
For some reason, the run-time names of array classes are different from how you specify them in the source code -- an array of ints is int[] in the source code but "[I" at run time. I can't imagine why this is.
A Very Subtle Point:
If you have a variable dogList of type Dog[],
then you can also assign dogList to be an array of type
SeeingEyeDog[]
assuming SeeingEyeDog is a kind of Dog.
But then you need to be careful that you won't be hit by the following
potential run-time problem: If you say dogList[3] = stupidDog
(which looks fine to the compiler as long as stupidDog
is a kind of Dog), an ArrayStoreException
can be thrown, since an array of type SeeingEyeDog[] cannot
contain stupidDog if stupidDog is not a
kind
of SeeingEyeDog.
If an automatic variable is not initialized before it is used, that is a compile-time error. Here's how the compiler decides whether something is initialized:
Change all values (except for boolean constant expressions) to "blah". Then, see if you can still tell that the variable must necessarily have been assigned, considering just the possible flows of control (including boolean-switched evaluation like &&, ||, ?...:). Also, consider try statements to be capable of immediately throwing any exception.int b; | | int b;
while (3>5) { | | while (false) {
b = 3; | | b = blah;
} | | }
foo(b); | | blah(b); // b not initialized
| |
int c; | | int c;
if (flag) | | if (blah)
c = 14; | | c = blah;
else | | else
c = 17; | | c = blah;
foo(c); | | blah(c); // c is initialized
| |
int d; | | int d;
if (flag) | | if (blah)
d = 20; | | d = blah;
if (!flag) | | if (blah)
d = 30; | becomes | d = blah;
foo(d); | | blah(d); // d not initialized!
| |
int e; | | int e;
if (flag || !flag) | | if (blah || blah)
e = 5; | | e = blah;
if (flag && !flag) | | if (blah && blah)
foo(e); | | blah(e); // e not initialized!
| |
boolean f; | | boolean f;
if (flag && (f=true)) | | if (blah && (f=true))
foo(f); | | blah(f); // f is initialized
| |
boolean g; | | boolean g;
if (flag || (g=true)) | | if (blah || (g=true))
foo(g); | | blah(g); // g not initialized
| |
int t; | | int t;
try { | | try {
t = 5; | | t = blah;
foo(t); | | blah(t); // t is initialized
throw(new MyException()); | | throw(blah);
} catch (MyException e) { | | } catch (blah) {
foo(t); | | blah(t); // t not initialized!
} | | }
if (getParameter("side") != null) side = (new Integer(getParameter("side"))).intValue();Strings
int theLen = "A String".length();The + operator concatenates strings, promoting first if necessary.
Note that if you declare a variable inside a loop, then it is undefined for the part of the loop prior to its declaration, and its initialization, if any, will be performed for every pass of the loop.
[[prioritized list of ops]]
Labeled Break and Continue
A block or statement can have a label, say foo:{some code}.
Then, if, inside the labeled part, a break foo; is encountered,
the labeled section will immediately be exited. If a continue
foo; is encountered, the labeled part (which must be a for,
do,
or while statement) will immediately be continued.
static means the method is a class method -- it may
be invoked by ClassName.methodName as well as instance.methodName
(there is no difference -- use whichever is handier).
A static method therefore cannot use instance variables, or this,
since there may not even be any instance in existence!
abstract means the method has no code -- a subclass must override (redefine) the method, supplying code. In this case, the declaration is followed by a semicolon instead of code.
final is the opposite of abstract -- it means that subclasses are not allowed to override the method.
native means the the code for the method is written in some language other than java. We will not discuss this sort of weirdness.
The return type may be a type, or void. If the return type is void, then no value is returned. No return statement is needed, and if there is one (for example to return from a point other than the end of the function's code), it must omit the value. (It may not even specify a "void" value, e.g. return voidFunction(3,5); is not allowed.)
[accessSpecifier]
[static] [final]
[transient] [volatile] type varName [= init];
static means the variable is a class variable -- there
is only one copy of this variable, no matter how many instances exist.
Instances do not have their own copy of this variable -- they all share
the one unique copy.
The variable may be referenced as ClassName.varName
as well as instance.varName (there is no difference --
use whichever is handier).
final means that the value of the variable, specified by the init at the end of the declaration, will never change. This means the compiler can treat it as a constant, rather than creating storage for it, and perhaps make other optimizations as well.
transient means that the variable should not be considered part of the object when the object is being archived. What does this mean? Who knows. Current versions of Java all ignore this anyway!
volatile means that the variable can be changed asynchronously, and the compiler should specifically avoid optimizations that assume the variable's value to be, say, the same as what it was the last time you looked.
The init is executed when a new instance is created (or when the class is created, if static), prior to the execution of the constructor.
There are four scope levels that can be specified:
private | package | protected | publicA class's code can always access member variables of objects of that class -- but if the variable is private, then nothing else can see it, even within the package.
Are these compile-time or run-time restrictions? Run-time!
That is, at run time you can ask what methods a class implements, and
so on.
"Static" variables or methods are class variables and methods.
What does a public method mean for a non-public class?
For example, interface methods must be public. But why, if the
interface isn't public?
An abstract method may only appear in an abstract class.
You can't have an abstract static method. Why?
All methods in a final class are automatically final. The same is true
for private methods.
If a method is static and has no type or name, then it is init code
for the class.
Why can't a constructor be synchronized (or anything else)?
You declare an interface like this:
[public] interface Pokable [extends Botherable,
Malleable] {
int JAB = 8, TICKLE
= 3;
void pokeMe(PokerObject
poker);
boolean beenPoked(void);
}
If "public" is present, then the interface will be available outside
the package.
Extended interfaces can have methods or constants hidden by the new
interface.
All the methods are automatically "public abstract".
All the constants are automatically "public static final".
class Pig extends LiveStock implements Pokable,
Feedable {
void PokeMe(PokerObject
poker) {
}
void FeedMe(FoodObject
feed) {
}
boolean beenPoked(void)
{
return true;
}
}
Interfaces may be used as variable types!
new Point(3) creates and returns a new instance of the Point class.
It's code sets this.x, this.y, or whatever it needs to. It behaves
syntactically as if it is type void.
The method Point(int n) is a "constructor" because it has the same name as its class -- it gets called automatically (by "new") after the instance has been created, to give the instance a chance to do some automatic initialization of its state. There can be different constructors (distinguished by taking different numbers or types of arguments).
How can one constructor call another (to avoid duplicating initialization
code)?
The first line of a constructor may be this(args); or super(args);,
indicating that another constructor should be executed before the remainder
of the body of this constructor is executed.
If there is no such first line, then super(); is assumed.
If no constructor is supplied, then one with no arguments, calling
super(), is assumed.
The method finalize() is a "destructor" because its name is "finalize"
-- it gets called automatically by the garbage collector just before the
instance is destroyed, to give the instance a chance to do some automatic
"finalization" (the opposite of "initialization"), such as closing streams.
It should probably end with
super.finalize();
After you understand the syntax and semantics of the Java language, the main thing you will spend time learning about is the large set of classes that are a standard part of Java. You will learn about classes that enable you to get input, produce output, and do countless other things. These classes are supplied as packages.
You can make a package like this:
package graphics; // applies to this whole file
interface
Draggable {
. . .
}
class Circle
{
. . .
}
class Rectangle
{
. . .
}
All files containing the package graphics line will be considered
to be in your graphics package.
That line must be the first one in the file???
The resulting .class files must be placed in a "graphics" directory
on the CLASSPATH.
The package name can have internal period-separators.
If you don't specify a package, you are in the "default package", which
is always imported.
Remember that only public methods and interfaces are visible outside the package.
You can import by:
import graphics.Circle;
or
import graphics.*;
What does import really mean???
If the same class is in two packages you have imported, you can specify
which class you intend by prepending the package name to the class name:
graphics.Circle
A natural idea, especially when you want your program to do two unrelated activities, is to let there be more than one gnome. Each gnome can then follow code around, line by line. Of course, you will need to take care that they aren't each messing with variables that the other is using -- that would cause a lot of confusion for the poor gnomes, and their algorithms would be ruined!
All the object-oriented metaphors talk about the "object" performing the activities described in its methods. Don't be fooled! Gnomes do the work. For example, one object can do two things at once, if two gnomes are executing its code. If an object doesn't have any gnomes doing work for it (and this is usually the case for most objects, since there are typically many more objects than gnomes), then it can't do anything at all until a gnome arrives on the scene. And in fact, the gnome manipulates the object, not the other way around. The only "control" the object has over anything is that in some sense the code represents the will of the object. A method is something that the object might be asked to do. The code for the method represents how that kind of object chooses to respond to that request, and it is executed by any gnome that is sent to that method. Objects never get to do anything except respond to requests and messages. (Often the requests are actually sent from the object to itself. For example, an object that is asked to go to the next room might first ask itself to stand up, and then ask itself to walk in a certain direction.) "Being asked to do something" means that a gnome is sent to the object's method for responding to that request. When the gnome is done handling a request, it returns to the higher-level request that it had previously been working on. The object-oriented jargon talks about a "method" being "invoked" or a "message" being sent. Really, a gnome is sent. Sometimes the gnome is sent with a message, and sometimes it is sent with a request. The only difference is in your mind. A gnome always arrives just to perform a specific method, and when it is done, it leaves. They have an incredibly strong work ethic.
In Java, each gnome (each thread) has a Thread object associated with it. This object stores the name of the thread, along with any other knick-knacks a thread might desire. The thread itself is just running around mindlessly executing code, and has no memory or sense of self. Actually, that's not quite true. It has its own call stack, where it keeps passed arguments, local variables, and return values. And it knows where its Thread object is. That is where it stores its name and so on. This can come in handy for example if you have different instructions for different threads (you would have instructions like "if your name is Sam, do such and such").
Thread.currentThread() is an introspective class method -- if you send a gnome off to execute this method, then it will come back with its associated Thread object.
new Thread(name) creates a new soulless instance of the Thread class,
a "missing gnome" file.
If a gnome X executes the start() method for a "missing gnome" object,
then the "missing gnome" comes into being as a real live gnome Y, and Y
runs off to execute its run() method. The original gnome X just returns
to its caller, without worrying about what the new gnome is up to.
If the new gnome Y ever returns from the run() method, it is automatically
and painlessly terminated.
When Y comes into being, it looks for its run() method. It may
have one itself, if it is a subclass of Thread that has a run() method.
But it might not have one -- then it looks for a run() method of its "target"
object. What is its target?
new Thread(obj,name) makes a new instance of the Thread class, which
has obj as its "target". The class of obj should implement Runnable (have
a run() method).
There are various methods of the Thread object that control the activity
of the associated gnome:
(I think they all also exist as class methods, operating on the gnome
that executes them.)
The sleep() method causes the gnome to immediately fall asleep for the specified number of milliseconds. When it wakes up, it will continue where it left off.
The suspend() method puts it to sleep until someone else executes its resume() method.
If the thread calls wait(), then it sleeps until that thing calls notify() or notifyAll().
If a gnome is supposed to do some I/O on a device that is busy, it will fall asleep until the device is free. This is probably implemented with the above strategies.
Gnome 1 Gnome 2 ------------------------- ------------------------- pick up the scissors pick up the scissors put fabric 2 in scissors position fabric correctly put fabric 1 in scissors cut fabric position fabric correctly put fabric down cut fabric put fabric downHere each gnome is doing something that by itself seems sensible. But at the same time, another gnome is messing around with the same scissors, and the result is disaster! Gnome 2 is cutting the wrong fabric in the wrong place, and Gnome 1 winds up snipping thin air! This just goes to show how brainless threads are. They are so busy working that they never look up to see if what they're doing makes any sense.
People usually solve this in the following way: Whoever gets to the scissors first gets to use them until they are done, at which point they give the scissors to the other person, who had to idly wait until they got the scissors.
From an object-oriented point of view, we might have an object theScissors, with a method cutFabric(). To solve the problem of thread brainlessness, theScissors would know that there are certain activities that are only safe for one gnome to do at a time, such as cutting fabric. Such activities (methods) are marked with the keyword "synchronized". Any time any thread wants to start executing synchronized code, it will first make sure no one else is doing so for that object. If someone else is doing so, it has to wait its turn. But once it is executing the synchronized code, it can be sure nobody else will do so until it has finished.
The way this works is that there is a solid gold baby monitor excavated from the tomb of Cheops. This item is popular with objects, but since the real article is in the London museum, each object just has a little gold-tone plastic replica. There is a bizarre tradition dictating that gnomes may only enter "synchronized" code if they have the object's baby monitor. Only one gnome can have the monitor at a time, so if a gnome enters synchronized code on behalf of a certain object, no other gnomes may do so until it has finished with the synchronized code, thus relinquishing the monitor.
synchronized (myObject) {code executed when myObject's monitor is obtained}wait() -- sleep until notified (letting go of monitor)
notify(), notifyAll() -- wake up all waiters.
These can only be called when you have the monitor -- why???
Are constructors automatically synchronized? The docs say it can't matter, since nothing else can see the object before the constructor finishes. That doesn't seem right, though. ???
try {code that might throw exceptions} catch (MyThrowable var1) {...} catch (Throwable var) {...} finally {...}If an Error or Exception is thrown, then the first (if any) applicable catch is executed. In any event, the finally block is executed, even if the remainder of the function will be skipped due to an active exception..
Here's how to indicate that your routine may emit a throwable instead of its return value:
public void writeList throws IOException, ArrayIndexOutOfBoundsException {...}Here's how things are thrown:
throw aThrowable;Runtime exceptions can happen from any function -- functions do not need to declare that they might throw them.
There are two built-in kinds of Throwable:
Let's consider the FileNotFoundException. You might think that a careful program could first check to make sure the file exists, and only open it if it exists. But even this is not 100% safe -- another program could delete the file after you checked that it exists, but before you opened it. The only way to really tell whether you can open it is to just try, and see whether you succeed or fail. In Java, failure is indicated by an exception being thrown.
As such, the compiler requires that such exceptions be specified in the function declaration if they might be thrown by the function. So if you have a function that opens a file, and it doesn't bother to catch the file-not-found exception, then the exception will be thrown to the calling function -- the function declaration must specify this, so that callers know to expect the exception.
Instead of a simpler GUI model, we are faced with yet another windowing system whose complexity is comparable to previous windowing systems. That is, it is a huge bureaucracy of events, drawing commands, and so on.
AWT == Abstract Windowing Toolkit
We will try to separate the bureaucracies from each other to simplify the picture.
import java.applet.Applet;
The first three (code, width, height) are required. The rest are
not. The order doesn't matter. The last three are the same
as for the IMG tag. The html keywords are all case-insensitive.
"Codebase" lets you specify an absolute url. (The default is
the url of the html page.) The "code" file must be relative to this,
not absolute.
In the "param" tag, the "value" field is always passed to the applet
as a string, regardless of whether quotes are used.
The java code can read a parameter like this:
String outerMethod = myApplet.getParameter("OuterMethod");
This will return null if there is no such parameter supplied!
This must be done in the applet's init() or later -- doing it in the
constructor fails badly.
You can get values of parameters inside the APPLET tag in just the
same way.
Methods such as Integer.parseInt (throws NumberFormatException) can
be useful for turning the string into a preferred type.
Extremely interactive environments will be able to show a page writer
the following information if you supply this method in your applet subclass:
public String[][] getParameterInfo() {
String[][] info = {
// Parameter Name Kind of Value Description
{"InnerMethod", "int",
"number of approximations to make"},
{"OuterMethod", "activity",
"bubbling, snorting, or whizzing"}};
return info;
}
Events are passed up the container heierarchy by default.
You can look at, alter, or stop an event before it continues up the
heierarchy.
An event arrives at a component in the handleEvent() method, which dispatches the event to the appropriate handler according to its type. If you override this, you probably want to return super.handleEvent to take care of the dispatching (e.g. otherwise action events can't get generated).
import java.awt.Event;
An Event e has a type, target, timestamp, location, keyPressed, data,
modifierKeys.
e.type
What is a LayoutManager?
Every
There are several pre-supplied layout managers, or you can write your
own.
"Double buffering" is just drawing into an image, and then painting by copying the image. See Image Bureaucracy.
A Graphics object represents a drawing context, and lets you draw empty/filled
rectangles, arcs, lines, ovals, polygons, text, and images. The following
examples operate on graphics object g.
Coordinates are in pixels, with y increasing as it goes down.
Even the init is in the update() method because until then we don't
know what size we are.
stupidities:
flow control not improved -- it's still a pain to decide whether every
linked list in a square array contains a predator
interface methods must be public, so the compliant methods must be
public,
so a public class is forced to expose interface-related methods regardless
of whether they should be visible outside the package