|
|
The BannerCo-Op - 1-1 Exchange + Cash |
Sun Certified Programmer Examination Revision Book
©1999 Dylan Walsh
Number of hits:
Disclaimers
No claims are made about the accuracy of this document and no responsibility is taken for any errors. The exam objectives below, in green, are quoted from Sun Microsystems website. The author has not corrected any errors in the text of those objectives (of which there are many, both grammatical and factual). Also there are parts quoted from the Javadocs, also the property of Sun Microsystems.
If you find any errors, please email dylanwalsh@engineer.com
Introduction
The purpose of this document is to provide a basis for revising for the Sun Certified Programmer examinations not to teach the Java language or the topics required for the exam. It is designed to collect all the essential information you need to retain, in one place, and is designed for someone who has already finished their own study, and is about to take the exam.
If you are just starting to prepare for the exam, then I recommend the following steps:
Java 1.1 Certification Study Guide, by Roberts and Heller
Java Certification for Programmers and Developers, by Barry Boone
You don't need to buy both, but I found that a good way to study was to do one chapter from each every evening. I did chapters on different topics, which made it more interesting and meant that I revised the same topic later in the other book. If you are going to buy just one, then get the Roberts and Heller one, it is widely regarded as the best. Both of these are designed for 1.1, but there are new versions for Java 2 in the pipeline (search on Amazon).
Useful links:
Suns own certification site, has FAQs, objectives and sample questions: http://suned.sun.com/usa/cert_test.html
The Java Certifcation Study Group, contains a good discussion forum: http://www.woj.com/tech/javacert/
Marcus Greens Site has exams, FAQs, tutorials:http://www.software.u-net.com/
Joes page, has an SCJP tutorial: http://www.geocities.com/SiliconValley/Network/3693/
The JavaRanch, has a nice rules exam, and lots of cows: http://www.javaranch.com/
The Exam
Here are just a few comments on the exam itself. Firstly, time will not be a problem, you should have time to answer all the questions, and review them, and possibly be able to leave early. It will really be an issue of whether you know/understand what it required. Generally, the questions in the real exam are a lot better than the mock exams which are going around: They are unambiguously worded, the sample code is usually short, and the slant of the questions is towards whether you understand the principles rather than whether you have memorized a lot of methods etc. The majority of the questions are on the core language itself rather than its APIs i.e. language fundamentals rather than AWT, Input/Output, java.lang etc. Of course, you do need to study these topics to get a pass mark.
About This Document
This document is structured around the objectives for the exams. For each objective, I have attempted to list all the bare-bones information you may need to remember for the exam.
The objectives for the Java 2 platform are much more concise and less detailed than those for 1.1, so this document is based around the latter. Where there are any differences in the Java 2 exam, I have described them.
Section Title: Language Fundamentals
Java 1.1: Only methods defined in the current class are listed, not those inherited from its super class. So if you can't find a method you think should be there, search up the class inheritance hierarchy.
The new Javadoc format in the JDK 1.2 shows inherited members (in their own tables), so this point may not be relevant to the Java2 platform exam.
The order is as follows: package declarations, import statements, then class definitions. The order of public vs. non-public class definitions does not matter. However, note that with Suns JDK, you can only have one top-level public class per source file, and the name of the file must be the same as the name of the public class. For example;
package acme.applications.userinterfaces;
import java.awt.*
public class SomeClass {
etc.
[The following rules apply to creating a main() method, which allows you to run the class as an application. You can create any number of methods in a class called main (overloading), which take other arguments, are not public and static, or return a value. To be able to run the class, however, there must be one method called main that takes an array of Strings as an argument, and that method must be public, static, and not return a value. Otherwise you will get a runtime error when you try to execute the class]
The main() method must be public, static, not return a value, and take an array of strings. Either of the following two examples are the accepted way of declaring main (depending on who you listen to):
public static void main(String[] args)
public static void main(String args[])
Note that 'args' is just a common name for the array, and you can call it anything you like. Also:
static public void main(String[] args)
is perfectly legal and will compile.
The command line arguments, after the java command and the name of the program, are placed in the String array, starting at array element zero.
Java keywords (check that you know what each of these does, if not, find out before you take the exam!):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The keywords in red are reserved but not used.
Note that while they are not keywords, the boolean and null literals (true, false and null) cannot be used as identifiers.
[Note that Roberts & Heller lists true and false as keywords on page 4, but these are literals, not keywords]
Class level variables (variables declared in the class, but outside of any methods, i.e. static and instance variables) are automatically initialised to a default value, if no explicit assignment has been made. The defaults are 0 for numerical types, '\u000' for chars, false for booleans, and null for objects.
The elements of an array are always (even inside a method) initialised to their default values when no explicit assignment has been made to the element.
If you do not initialise a variable declared in a method to some value, you will get a compiler error.
Primitive Type |
Size |
Range of Values |
byte |
8 bit |
-27 to 27-1 |
short |
16 bit |
-215 to 215-1 |
int |
32 bit |
-231 to 231-1 |
long |
64 bit |
-263 to 2 63-1 |
char |
16 bit |
to '\uffff'
(0 to 216-1 ) |
Identifiers may contain only letters, numbers, dollar signs, i.e. "$", or underscores, i.e. "_". The first character cannot be a number. Obviously an identifier cannot have the same spelling as a keyword or the boolean and null literals (true, false and null) as described earlier.
Octal literals begin with zero e.g. 013042 (and obviously only digits 0-7 are allowed). Hexadecimal literals begin with zero and an 'x' e.g. 0x23e4A (digits allowed are 0-9 and a to f, the 'x' and the letters can be upper or lower case).
String duh = "This should be obvious, but I'll include an example anyway."
Use \u followed by four hexadecimal digits representing the 16 bit unicode character e.g.
char x='\u1234'
Java also supports certain escape codes for special characters such as '\n' for newline. See a textbook for more.
Section Title: Operators and Assignments
These operators are followed by a number which defines by how many bits the number is shifted.
>> performs a signed right-shift, that is, if the most significant (i.e. first on the left) bit is 1, then when it right-shifts the bits, it fills in a 1s on the left. If the most significant bit is 0, then when it right-shifts the bits, it fills in a 0s on the left. As the first bit represents the sign of a number (positive or negative), this preserves the sign of the number.
>>> performs an unsigned right-shift, it always fills in 0s on the left.
<< performs a left-shift (it always files in 0s on the right).
Adds. If any of the variables are Strings, it converts the non-Strings to Strings, and concatenates (joins) them.
With Objects, == determines whether the variables reference the same object in memory, rather than comparing their contents in a meaningful way. If you assign a=b, then a==b will evaluate to true, where a and b are objects.
Note that if you construct two Strings with the same String literal, without using the new keyword, e.g.
String a = "Hello"
String b = "Hello"
, then Java creates only one String object, so a==b evaluates as true.
Unless it is overridden, the equals() method behaviour in Object, and therefore inherited from it, performs the same reference comparison as the == operator. However, the Boolean and String classes override this with a more meaningful comparison. equals()returns true, in Booleans if the two objects contain the same Boolean value, and in String if the Strings contain the same sequence of characters.
Note that StringBuffer does not override the equals() method, so if you use this method, it will not compare the actual text characters that the StringBuffers contain.
Just a quick note on the second two operators: && (AND) and || (OR) are the short circuit operators, which do not evaluate the second operand if it is not necessary. AND is only true if both values are true, therefore if the first is false, the result is false, and there is no need to evaluate the second part. OR is true if either value is true, therefore if the first is true, the result is true, and there is no need to evaluate the second part.
Primitives: You cannot assign booleans to any other type. With the exception that you cannot assign a byte to a char, you can assign a variable of type X to type Y (i.e. Y=X) only if Y is 'wider' than X. 'Wider' means that the primitive type can contain a wider range of values. The primitives, in order of 'width' are char/short, int, long, float, double. Note that you cannot assign a char to a short or vice versa.
Objects: You can assign object X to object Y (i.e. Y=X) only if they are of the same class, or X is a subclass of Y (called "upcasting").
This objective is not very specific, but the following information may help. In an arithmetic statement, variable may be widened automatically, to evaluate the expression (note the variables themselves aren't change, i.e. byte b is still a byte afterwards, but for its calculations Java uses a widened value). This is called promotion. Bytes, shorts and chars are always converted to ints, in unary (e.g. x++)or binary operations (e.g. x*y). For binary operators, if one operand is wider, the other is widened to the same type.
When passed to a method, primitives may be promoted, and objects may be upcast, to the type/class that the method takes, if possible. For example, if a method takes an int as an argument, and you pass it a byte, the value passed to the method is the byte converted to an int. Note that the variable in the calling method is unaffected (passing by value). The rules for when this is allowed are as per the objective "Determine if an assignment is permitted between any two variables of possibly different types" above.
Section Title: Declarations and Access Control
For example, either
int[] x;
are legal positions for the brackets. To declare a multidimensional array, use mutliple sets of brackets, e.g. int i[][]; declares a two dimensional array.
Arrays are objects. Use the new keyword to construct them. For example having declared an array i:
int[] i;
you then construct the array and assign it to i as follows:
i = new int[10];
int i[] = new int[10];
An example:
int somearray[] = new int[15];
for(int j=0; j<somearray.length;j++){
somearray[j]=j;
}
An example:
char c[]= new char[] {'a','b','c','d','e'};
If you are usure of this, see a textbook.
public -
can be accessed by any other class.abstract -
cannot be instantiated, is allowed to contain abstract methods.final -
cannot be subsclassed.
private -
can only be accessed from inside the class. Private members are not inherited by subclasses. Inner classes can be declared private.protected -
can only be accessed by classes in the same package or subclasses of this class.public -
can be accessed by any other class.static -
belongs to the class rather than any particular instance of the class. For variables, effectively, there is just one copy of this variable for all instances of the class, and if an instance changes the value, the other instances see that new value. For methods, it means the method can be called without having created an instance, but you cannot use the this keyword, or refer to instance variables and methods directly (without creating an instance and referring to the variable/class in that instance). For inner classes, it means they can be instantiated without having an instance of the enclosing class, but as with static methods, the methods of the inner class cannot refer to instance variables or methods of the enclosing class directly.final -
cannot be changed. Variables are constants, methods cannot be overridden, classes cannot be subclassed.native -
a method which is not written in java and is outside the JVM in a library.abstract -
a method which is not implemented.
Default constructor takes no arguments e.g. classname() where classname is the name of you class. A default constructor is automatically created only if you do not create any constructors in your class. If you create a non-default constructor (i.e. one that takes an argument), then you may have to create a default one yourself, if you want there to be one. All constructors call the default constructor of its parents class (if there is one), and so on up the hierarchy to Object, unless you specify a different constructor in the parent using super(…) or this(…), which must be the first line in the constructor.
static -
belongs to the class rather than any particular instance of the class. For variables, effectively, there is just one copy of this variable for all instances of the class, and if an instance changes the value, the other instances see that new value.final -
cannot be changed. Since Java1.1 you can declare the variable without assigning a value. Once you assign a value, you cannot change it.
A very technical, but good, reference for these kinds of issues is the Java Language Specification which is available at the following URL:
http://java.sun.com/docs/books/jls/html/index.html
Section Title: Flow Control and Exception Handling
Consult a text book for the basics of these, if unsure. If you do know the basics, here are two things to watch out for:
Number 1
Be wary where if is used without braces, and with an else statement (this is referred to as the dangling else problem, and occurs in C and C++ aswell). The following example is from Boone (p.154):
if (result >=0) |
|
|
|
if (result > 0) |
|
|
|
System.out.println("positive"); |
else |
|
|
|
System.out.println("negative"); |
|
The indentations are misleading. It might appear that the above code will print "positive" if result is greater than 0, "negative" if is less than zero, and print nothing if result is equal to 0. In fact, it will print "positive" if result is greater than 0, it will print nothing if is less than zero, and print "negative" if result is equal to 0. This is because the else statement belongs to the second if statement, and only executes if result >=0 but not if result>0, in other words if result equals 0. Using braces (curly brackets) would fix this. The following indentation shows the real relationship, of course the compiler doesn't care about indentation:
if (result >=0) |
|
|
|
if (result > 0) |
|
|
|
System.out.println("positive"); |
|
else |
|
|
|
System.out.println("negative"); |
Number 2
After switch/case construct has executed the correct case, it will continue to execute all those after it (including default: if it is there, after the selected case) on to the end of the switch/case block, unless you put in a break, return or throw statement. This is referred to as "falling through". For example:
switch (a) {
XXX
case 1:XXXXXX
System.out.println("one");XXX
case 2:XXXXXX
System.out.println("two");XXX
case 3:XXXXXX
System.out.println("three");XXX
default:XXXXXX
System.out.println("some other number");}
If a is 1, this will print "one", "two", "three" and then "some other number" in succession. If a is 3, this will print "three" and then "some other number".
In some cases, this kind of behaviour is desirable, but here it isn't. This block of code fixes it:
switch (a) {
XXX
case 1:XXXXXX
System.out.println("one");XXXXXX
break;XXX
case 2:XXXXXX
System.out.println("two");XXXXXX
break;XXX
case 3:XXXXXX
System.out.println("three");XXXXXX
break;XXX
default:XXXXXX
System.out.println("some other number");}
Note that in switch blocks, it is legal to put default: anywhere in the block, it doesn't have to be the last one.
The argument for an if() statement must be a boolean or an expression which evaluates to a boolean. A common mistake is to use a single = rather than == to compare values. The following gives a compiler error:
public static void main(String[] args) {
XXX
int a=1;XXX
if(a=2) System.out.println("a is two");}
a=2 assigns the value 2 to a.
The argument for a switch statement must be a byte, a char, a short or an int, or an expression which evaluates to one of those.
An example:
for(int i=0;i<3;j++){
XXX
System.out.println("i is "+i);XXX
for(int j=0;j<3;j++) {XXXXXX
System.out.println("j is"+L);XXX
}}
Will print:
i is 0
j is 0
j is 1
j is 2
i is 1
j is 0
etc.
Note: Don't get thrown if the for loop uses pre-increment instead of post-increment i.e. for(int i=0;i<3;++j) instead of for(int i=0;i<3;j++). This does not make any difference to the behavior of a for loop.
break
will cause the current loop to be abandoned. continue causes execution to skip the rest of the code in the current iteration of the loop, and start at the top of the loop with the next iteration.These (unlabeled) versions will only affect the execution of loop that they are in. If you have nested loops, and want to break out of, or skip to the next iteration of, an outer loop, from an inner loop, you used the labeled versions. These jump to the wherever the label is, allowing you to break out of, or skip several nested loops, by placing the label in front of the outer loop.
Place code which is likely to throw an exception inside a try { } block. Create one or more catch() { } blocks with code to deal with the types of exceptions that might be thrown in the try block. The type of exception goes inside the round brackets of the catch() statement, as you would when declaring a method.
Exceptions are objects, which belong to a class hierarchy. If the exception thrown is an instance of the class, or a subclass of the class, specified in catch(), that catch block is the one executed. Your catch() block therefore can handle a range of exceptions if they are subclasses of the class specified. If you want to handle one specific subclass one way, and all the other subclasses differently, put a catch statement for the specific subclass first, and a more gereral catch block for the superclass second. Then when an exception is thrown, if the exception is a member of the subclass, that catch block only executes, but if it is a different subclass of the parent class, the general catch block executes. If you put the superclass first, you will get a compiler error.
finally
blocks execute no matter what, in other words, whether the code executes without an exception, or an exception is thrown and successfully caught, or an exception is thrown and not caught. This is useful because, except for code in a finally block, if an exception is thrown and not caught, the execution of the rest method is abandoned.One (probably not important for the exam) thing which could stop a finally clause from executing, is a call to System.exit(0).
If an exception is thrown, then the rest of the code in the try block is not executed. If the exception is not caught correctly, then after the finally block executes, the rest of the code in the method is not executed.
For example:
void mymethod(int i) throws Exception { }
Methods can throw more than one class of exception, you list all the exceptions after the throws keyword, separated by commas.
Essentially, a method can throw the same or fewer, but not more, exceptions than the superclass method it is overriding. This has to do with object orientation, if you could broaden the number of exceptions in the subclass method, anything which can deal with the superclass might not be able to deal with the subclass, because the are new exceptions there that it isn't written to handle. You want all members of subclasses to be able to be handled as if there were members of the parent class ("upcasting" or polymorphism).
The hierarchy of exceptions is important here, you can replace a exception class in the overridden method with one or more of its subclasses, but you can't replace it with its superclass. To do this would be to broaden the range of exceptions the method could throw.
For example:
throw new SomeKindOfException();
Section Title: Overloading, Overriding, Runtime Type, and Object Orientation
Briefly, 'is a' should be implemented using inheritance, 'has a' should be implemented using containment. This objective is conceptual, consult a textbook for more.
SomeObject instanceof SomeClass
evaluates as true if SomeObject is an instance of SomeClass, or is an instance of a subclass of Someclass. Otherwise it evaluates as false.
SomeObject instanceof SomeInterface
evaluates as true if SomeObject is an instance of a class which implements SomeInterface. Otherwise it evaluates as false.
What identifies a method in the Java is not merely the name of the method, rather it is the name of the method and the arguments it takes. You must watch for any differences in the arguments list. If the arguments are different, you are dealing with a separate method. This is overloading. The fact that they have the same name means is only of significance to humans.
The return type is not part of a methods signature. You are only overriding if there is a method in the parent class with same name which takes exactly the same arguments. Then the method replaces the one from the superclass.
You cannot define two methods within a class with the same name and the same arguments.
Overloaded methods are really completely different and separate methods, so they can return completely different types.
The overriding method must return the same type as the method in the superclass. This is because in the subclass, the overriding method replaces the method in superclass, and polymorphism or "upcasting" would not work they returned different types (i.e. you should get the same return type as you would with the parent class, or else you can’t treat the subclass as the superclass).
If the object is an instance of the derived class, then the overridden version defined in the derived class is the one that is envoked. Look at this example:
class Animal {
XXX
void sayHello() {XXXXXX
System.out.println("Hello, I'm an animal.");XXX
}}
class Dog extends Animal {
XXX
void sayHello() {XXXXXX
System.out.println("Hello, I'm a dog.");XXX
}}
We are overriding the sayHello method with behaviour more specific to a dog.
The straightforward method calls are as follows:
Animal i = new Animal;
i.sayHello();
prints "Hello, I'm an animal."
Dog j = new Dog;
j.sayHello();
prints "Hello, I'm a dog." because we have overridden sayHello, and this instance is a dog.
However:
Animal k = new Dog;
k.sayHello();
prints "Hello, I'm a dog." Here we are creating an instance of Dog, but we are assigning it to an Animal reference [referring to an object as the base class is called "upcasting" and is useful as you can write methods that deal with instances of any of the subclasses]. Because the underlying object is really a Dog, the method in the derived class is the one that executes.
Note: This behavior only applies to instance (i.e. not static) methods. Variables and static methods do not "override", instead they "hide" the variable/method in the parent class. This means that the class of the reference, rather than that of the underlying object, that matters.
super.someMethod()
will call the version of someMethod() in the immediate super class. You cannot use something like super.super.someMethod() to call the method two steps up the object heirarchy.
These calls must be at the very start of the code in the constructor, therefore you can only make one of these types of calls. A call to the default constructor in the parent class is made by default, so super(arguments) is useful when you want to call a version of the constructor which takes an argument instead (there may not be a default constructor in parent class, in which case this call is necessary, or the code won't compile).
this() with or without arguments in brackets is used to call any of the other (overloaded) constructors defined in the class, before performing actions specific to current constructor being defined.
Place the class definition (for the inner class) inside another class definition (the outer class).
An anonymous inner class is defined where is it instantiated (in a method). An anonymous inner class must either implement an interface or extend a class, but the implements or extends keywords are not used. For example the following line causes the method to return an object which is an instance of an anonymous inner class:
return new SomeClass() { //body of the anonymous class goes here };
or the following calls someMethod(), passing an instance of the anonymous inner class:
someMethod(new SomeClass() { //body of the anonymous class goes here });
SomeClass() is not the name of the anonymous class (the class is anonymous!) rather is it the name of the class that you are extending or the interface you are implementing. You might like to think of an anonymous inner class as a really long new statement, which happens to contain a method definition, and so it should have a ";" at the end like the first example, unless it is inside method call brackets, like the second example.
These classes cannot define a constructor, as they do not have a name that you can use to declare the constructor method. If name() is a class, the default constructor of that class is called, if you want to use a non-default constructor instead, you supply arguments e.g.:
return new name(12) { //body of the anonymous class goes here };
will call the name class constructor which take a number.
Inner x = new Inner();
constructs an instance of Inner where Inner is an inner class defined in the current class.
You must create an instance of the outer class first. Given a class, Outer, containing an inner class Inner:
Outer.Inner y = new Outer().new Inner();
The above creates an instance of Inner called y, but it had to construct an instance of Outer first (which here does not have a name). The following example creates the Outer instance on a separate line, the syntax in the second line is the one you use when you already have an instance of the outer class.
Outer x = new Outer();
Outer.Inner y = x.new Inner();
If Inner is static, you can use:
Outer.Inner I= new Outer.Inner();
A non-static inner class has access to all member variables and methods of the containing class.
A static inner class is restricted in the same way as a static method: it cannot refer to instance variables and methods of the containing class directly (without creating an instance and referring to the variable/class in that instance).
If the inner class is defined inside a method, it has access to those method (a.k.a automatic or local) variables which are declared final.
Section Title: Garbage Collection
How and when garbage collection occurs is left up to the implementation of the JVM, all you can know is that an object becomes eligible for garbage collection when there are no longer any references to it.
finalize()
The finalize method of a class is called before it is garbage collected. The method takes no arguments and must return void, and throws Throwable.
An object is eligible for garbage collection when there are no longer any references to it. This can happen if a variable is assigned to a newly created object, but later is assigned to a different object, there is nothing pointing to the object. Or when a method exits, all the variables go out of scope, so all the objects are eligible for garbage collection, unless there is a reference to them somewhere outside the method.
Section Title: Threads
Define a class that implements Runnable, which means you must define a run() method in the class e.g.
class MyClass implements Runnable {
XXX
public void run () {XXXXXX
// Insert the code you want to run in a thread hereXXX
}}
run() must be public, with a void return type, and not take any arguments. Note that if run() is defined to take any arguments, then that is a different method and the Runnable interface hasn't been implemented!
Create an instance of the class, and construct a thread, passing the instance of the class as an argument to the constructor i.e.
MyClass mc=new Myclass;
Thread t=new Thread(mc);
To start the thread, use the start() method:
t.start();
Alternatively, you can create a subclass of the Thread class, and override the run() in the subclass:
class MyThread extends Thread {
XXX
public void run () {XXXXXX
// Insert the code you want to run in a thread here}
}
Then create an instance of the subclass, and start it running:
MyThread mt=new MyThread(mc);
mt.start();
There is only one method in the interface, run(), which must be implemented
in the class.
The run() method.
Call the start() method on an instance of the Thread class.
A thread can be in one of the following states:
a) Running
b) Ready - Waiting for a chance to run on the CPU. All threads enter this state before running. Threads with higher priorities may be preventing the thread from getting a chance to run (this depends on how priorities have been implemented in the particular Java Virtual machine)
c) Various waiting states (Waiting, Sleeping, Suspended & Blocked)
d) Dead - the run() method has completed (the thread can never be restarted)
Using the synchronized keyword in the method declaration, requires a thread obtain the lock for this object before it can execute the method.
synchronized void someMethod() { }
You can also make a block of code synchronized by using the synchronized keyword followed by the object or class, for which a thread must obtain the lock before it can execute this block of code:
// .. some code before the synchronized block
synchronized (someObject) {
// code
}
// more code…
The wait() method must be used in synchronized code. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up (i.e. move into Ready state) either through a call to the notify
method or the notifyAll
method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
notify()
moves one thread, that is waiting the this objects monitor, into the Ready state. This could be any of the waiting threads; the choice of which thread is chosen is an implementation issue of the virtual machine.notifyAll()
moves all threads, waiting on this objects monitor, into the Ready state.
The use of these methods, and synchronized methods or code blocks, ensure only one thread at a time can access parts of a class, and control how and when threads get this access. If you are unsure of how they interact, consult a textbook.
Section Title: The java.lang package
abs()
-Returns the absolute value of the argument. Overloaded for ints, longs, floats and doubles.double
value that is not less than the argument and is equal to a mathematical integer.
floor(double)
-Returns the largest (closest to positive infinity)double
value that is not greater than the argument and is equal to a mathematical integer.
max(value1,value2)
-Returns the greater of two values.min(value1,value2)
-Returns the smaller of two values.random()
-Returns a random number between0.0
and 1.0
.
round(double)
-Returns the closestlong
to the argument.
sin(double)
-Returns the trigonometric sine of an angle. The angle is in radians.cos(double)
-Returns the trigonometric cosine of an angle. The angle is in radians.tan(double)
-Returns the trigonometric tangent of an angle. The angle is in radians.sqrt(double)
-Returns the square root of a double value.
length()
-Returns the length of this string.toUpperCase()
-Converts this string to uppercase.toLowerCase()
-Converts this String to lowercase.[Note that toLowerCase() and toUpperCase() will return a reference to original string object if the it is already in lower case or upper case respectively. This is important for questions on the == operator and strings.]
equals(Object)
-Compares this string to the specified object. Returns true if the strings contain the same sequence of characters.equalsIgnoreCase(String)
-Compares this String to another object. Returns true if the strings contain the same sequence of characters, ignoring case.
charAt(int)
-Returns the character at the specified index. An index ranges from0
to length() - 1
.
concat(String)
-Concatenates the specified string to the end of this string.
indexOf(int)
-Returns the index within this string of the first occurrence of the specified character.indexOf(int ch, int fromIndex) - Returns the index within this string of the first occurrence of the specified character, starting the search at the specified index.
indexOf(String)
-Returns the index within this string of the first occurrence of the specified substring.indexOf(String, int)
-Returns the index within this string of the first occurrence of the specified substring, starting at the specified index.
lastIndexOf(int)
-Returns the index within this string of the last occurrence of the specified character.lastIndexOf(int ch, int fromIndex)
-Returns the index within this string of the last occurrence of the specified character, searching backward starting at the specified index.fromIndex - the index to start the search from.
lastIndexOf(String)
-Returns the index within this string of the rightmost occurrence of the specified substring.lastIndexOf(String, int)
-Returns the index within this string of the last occurrence of the specified substring.
substring(int)
-Returns a new string that is a substring of this string. The substring begins at the specified index and extends to the end of this string.substring(int beginIndex, int endIndex)
-Returns a new string that is a substring of this string. The substring begins at the specifiedbeginIndex
and extends to the character at index endIndex - 1
. Remember: substring gives you the substring from the first index, to the second index minus one.
trim()
-Removes white space from both ends of this string.
toString()
-Returns a string representation of the object. This method is inherited by all classes from Object. By default, thetoString
method for class Object
returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@
', and the unsigned hexadecimal representation of the hash code of the object. You can override it in your own classes to produce some useful string eg. debugging info.
For the Strings, toString() returns the String object itself.
The + operator to concatenate strings.
String objects cannot be changed. They are assigned a sequence of characters when they are constructed. Look at the following code:
String message = "Good";
When the first line executes, a string object containing "Good" is assigned to message.
[a new String object is constructed, unless the literal "Good" was used somewhere else, in which case the exisiting String is re-used. A consequence of this is the behaviour of the == operator which was describe under Language Fundamentals above, here is that information again:
Note that if you construct two Strings with the same String literal, without using the new keyword, e.g.
String a = "Hello"
String b = "Hello"
, then Java creates only one String object, so a==b evaluates as true.]
On the second line, " morning" is appended. But the String object containing "Good" cannot be changed, so a new String, containing "Good morning" is created and assigned to message.
Section Title: The java.awt package - Components and Facilities
The names of these methods are self-explanatory. Note that after you create a frame, there are not visible by default, you must use setVisible(true)before it can be seen.
getSize()
returns a dimension object, which contains two integer member variables, height and width.Obviously setForeground() and setBackground() take a color argument.
As there is no mechanism to set the number of columns a list has, I would assume that the above objective contains a typo, and should refer to rows, not columns.
The constructors for a List are as follows:
List(int rows)
List(int rows, boolean multipleMode)
multipleMode
is true
, then the user can select multiple items from the list. If it is false
, only one item at a time can be selected.
The constructors for a TextArea are in the next objective.
A TextArea
object is a multi-line region that displays text. The following constructors allow you to specify the preferred number of rows and columns:
TextArea(int rows, int columns)
TextArea(String text, int rows, int columns)
A TextField has a single line of text:
TextField(int columns)
TextField(String text, int columns)
The width of a "column" is equal to the width of a character, in the particular font being used. In the case of fixed pitch fonts, where all the characters are the same size, this is straightforward. For proportional fonts, the width of a column is equal to the average of the width of all the characters in the font. This means, for example, if you had text component with a proportional font and a width of 10 columns, if you use a narrow letter such as 'i', more than 10 'i's could be displayed.
[Sun Certified Programmer for the Java™ 2 Platform
Based on available information, these painting methods are not examined in the Java 2 Platform (Java 1.2) exam, so you do not need to know this objective] drawString(String str, int x, int y)
drawLine(int x1, int y1, int x2, int y2)
(x1, y1)
and (x2, y2)
in this graphics context's coordinate system. drawRect(int x, int y, int width, int height)
x
and x + width
. The top and bottom edges are at y
and y + height
. The rectangle is drawn using the graphics context's current color. drawImage(Image img, int x, int y, ImageObserver observer)
There are other versions of this method, but the above is the most common. It draws the given image with its top left corner at the given co-ordinates. The ImageObserver is an object which implements the ImageObserver interface. Note that the Component class implements this interface so you can use the component into which you are drawing the Image as the ImageObserver.
drawPolygon(int xPoints[], int yPoints[], int nPoints)
Draws a closed polygon defined by arrays of x and y coordinates. xPoints[]is an array of the x co-ordinates , yPoints[] is an array of the y co-ordinates, and nPoints is the number of points. In other words, the corresponding elements of the arrays combine to give the (x,y) co-ordinate of each point in the polygon.
drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
startAngle
and extends for arcAngle
degrees, using the current color. Angles are interpreted such that 0 degrees is at the 3 o'clock position. A positive value indicates a counter-clockwise rotation while a negative value indicates a clockwise rotation. width
and height
arguments. width + 1
pixels wide by height + 1
pixels tall. fillRect()
, fillPolygon() and fillArc() are filled versions of drawRect(), drawPolygon()and drawArc() respectively.Note that fillArc()draws a 'pie-piece' rather than a 'chord'. In other words, if for example, the arc is part of a circle (i.e. width and height are equal) the filled area goes from the centre of that circle, out between two lines, to the ends of the arc.
Calling the getGraphics() method on the Image object returns a Graphics context from the Image.
An Image is an off-screen bitmap. A blank image can be created, or an image can be taken from a GIF or JPEG file. While images can be scaled or filtered, they do not have drawing methods like those of the Graphics class. You must obtain a Graphics context from the Image to do any drawing on the Image. To display an Image you must use a Graphics object (use the drawImage()method).
Section Title: The java.awt package - Layout
Note that the second form, as far as the certification exam scope is concerned, is used with BorderLayout. The String is one of "North", "South", "East", "West" or "Center", which specifies which area of the component is to added to. However, the JDK documentation strongly advises the use of the Java 1.1 form. Which is asked in the exam I can’t say, but it is probably wise to be familiar with both. The 1.1 form, which is the only one used in Roberts & Heller (Boone only uses the above form) is as follows:
public void add(Component comp, Object constraints)
For BorderLayout, the second parameter is a String as above, or you can use one of the constants defined in the BorderLayout class, BorderLayout.NORTH, BorderLayout.SOUTH etc.
You set the layout manager that a container should use. That layout manger then implements the layout.
public void setLayout(LayoutManager mgr)
For example, in the code of an applet:
setLayout(new GridLayout());
creates an instance of the GridLayout class, and makes it the layout manger for the applet.
Worth noting are the default layout managers: FlowLayout for applets and panels, BorderLayout for frames. Containers always use these defaults after being created, unless you specify otherwise, they do not get the default layout manager from the containers they themselves are placed in, unlike other properties such as colour, font etc.
BorderLayout divides the container into 5 regions, and one component at a time can be placed in each (that component can be another container, which itself can contain multiple components). If you add a component to a region which already contains another component, only the latest component will be displayed. Components in the North and South are placed at the top and bottom respectively, and are allowed to be their preferred heights but are as wide as the container. East and West are on the right and left sides respectively, and are allowed to be their preferred widths. Their heights stretch from the North and South regions (if there is nothing in North or South, they go from the bottom to the top of the container). Center fills the remaining space, left after the other regions, in the middle. The component is stretched to fill this area.
How to add components to the regions of a container using BorderLayout is describe above, in the first object of this section. Note that if you don't specify a region, the component is added to Center. Therefore, for example, if you create a frame (default layout is BorderLayout), and add a button to it using the default add(Component)method, the button will fill the entire frame.
FlowLayout always allows components to be their preferred size [This is true even if the component is wider or taller than the container. A centered portion of the component is shown, with as much of the component being made visible as can be]. It places many components as it can on a line, with the first component starting on the left, until there is no more room horizontally, then it starts another line. By default the rows are centred in the container. You can specify how the rows are aligned using this constructor:
new FlowLayout(int alignment)
FlowLayout.LEFT
, FlowLayout.RIGHT
, or FlowLayout.CENTER
GridLayout divides its area into equally sized rectangles. When components are added to it, they are made the same size as their cell. Two constructors to be aware of are:
public GridLayout(int rows, int cols)
rows
and cols
can be zero, which means that any number of objects can be placed in a row or in a column. public GridLayout()
Creates a grid layout with a default of one column per component, in a single row.
Sun Certified Programmer for the Java™ 2 Platform
While it is not mentioned in the objectives, GridBagLayout is examined in SCJP 2.
GridBagLayout
There is a tutorial which includes using GridBagLayout, with AWT, at ftp://ftp.javasoft.com/docs/tut-OLDui.zip
GridBagLayout is like GridLayout, except that components can be different sizes (i.e. take up more than one cell in the grid) and you have a lot more options, hence it is more complex. To use GridBagLayout, you create an instance, and set it as the layout manager for your container, as with the other layout managers. You don't specify the number of cells when constructing an instance of GridBagLayout, the constructor is just the default GridBagLayout().
The twist is that you specify how the component is to be displayed using an instance of GridBagConstraints. The fields in this class contain all the options. For each component, you use the GridBagLayout setConstraints() method:
setConstraints(Component comp,GridBagConstraints constraints)
The values for each component are read from the GridBagConstraints object, so you can change the values after each component, and reuse the same GridBagConstraints instance for the next one. Then you add the component to the container e.g.
MyGridBag.setConstraints(componentX, MyConstraints);
add(componentX);
GridBagConstraints Fields:
[The constants (uppercase) listed below for use with certain fields are static field in the GridBagConstraints class, so you refer to them as GridBagConstraints.EAST for example.]
anchor
This field is used when the component is smaller than its display area. It determines where, within the display area, to place the component.(one of CENTER (default), EAST, WEST, NORTH, NORTHEAST, NORTHWEST, SOUTH, SOUTHEAST or SOUTHWEST)
fill This field is used when the component's display area is larger than the component's requested size. It determines whether to resize the component, and if so, how.
(one of NONE
(Default), HORIZONTAL, VERTICAL
, or BOTH)
gridheight
Specifies the number of cells in a column for the component's display area.(Use REMAINDER
to specify that the component be the last one in its column. Use RELATIVE
to specify that the component be the next-to-last one in its column.)
gridwidth
Specifies the number of cells in a row for the component's display area.(Use REMAINDER
to specify that the component be the last one in its row. Use RELATIVE
to specify that the component be the next-to-last one in its row. )
[Here REMAINDER acts somewhat like a carriage return. You add elements to the row, and when you use REMAINDER that marks the end of the line, and then the next components are added to the next row. Look at the examples in the tutorial or in the JavaDocs. Alternatively, you can use gridx and gridy to specify grid position when adding a component.]
gridx, gridy
Specifies the position of the component. The constantREMAINDER
(which is the default) specifies that this component be placed next to the previously added component. The top left cell has gridx=0, gridy=0.
insets
Specifies the external padding of the component, the minimum amount of space between the component and the edges of its display area. This field belongs to the Insets class which uses the following constructor:Insets(int top, int left, int bottom, int right)
Insets
object with the specified top, left, bottom, and right insets.
ipadx
Specifies the internal padding of the component, how much space to add to the minimum width of the component.ipady
Specifies the internal padding, that is, how much space to add to the minimum height of the component.weightx, weighty
Specifies how to distribute extra vertical/horizontal space respectively. This is a double, typically between 0 and 1, the default value is 0. If all the weights are zero, and there is extra space, all the components are bunched together in the middle.
Section Title: The java.awt package - Event Handling
Listener Interfaces
For information and comparison purposes, here is the list of Listener interfaces, and their methods. You do not need to memorize this table. Note the relationship between the Listener interface name, the Event type (which is the argument to the methods) and the 'add' method which belongs to the component classes.
Interface Name |
Event |
Methods in interface |
Add method |
ActionListener |
ActionEvent |
actionPerformed(ActionEvent) |
addActionListener() |
AdjustmentListener |
AdjustmentEvent |
adjustmentValueChanged(AdjustmentEvent) |
addAdjustmentListener() |
ComponentListener |
ComponentEvent |
componentHidden(ComponentEvent) |
addComponentListener() |
ContainerListener |
ContainerEvent |
componentAdded(ContainerEvent) |
addContainerListener() |
FocusListener |
FocusEvent |
focusGained(FocusEvent) |
addFocusListener() |
InputMethodListener |
InputMethodEvent |
caretPositionChanged(InputMethodEvent) |
addInputMethodListener() |
ItemListener |
ItemEvent |
itemStateChanged(ItemEvent) |
addItemListener() |
KeyListener |
KeyEvent |
keyPressed(KeyEvent) |
addKeyListener() |
MouseListener |
MouseEvent |
mouseClicked(MouseEvent) |
addMouseListener() |
MouseMotionListener |
MouseEvent |
mouseDragged(MouseEvent) |
addMouseMotionListener() |
TextListener |
TextEvent |
textValueChanged(TextEvent) |
addTextListener() |
WindowListener |
WindowEvent |
windowActivated(WindowEvent) |
addWindowListener() |
[To save typing, there is the option of using Adapter classes, e.g MouseAdapter for the MouseListener interface. These are classes which have empty methods for all the methods in the Listener. You extend them, and then overwrite the methods you are interested in, saving the effort of typing other methods]
The only Event class that has methods for all of the above is MouseEvent.
Affected Component:
There are two methods that fit this description. From looking at the source code, it appears they perform the exact same function.
All ComponentEvent subclasses implement this method:
public Component getComponent()
All events implement this method:
public Object getSource()
Mouse Position: MouseEvent implements these methods: public Point getPoint()
public int getX()
public int getY()
Nature:
All AWTEvent subclasses implement this method:
public int getID()
Time:
InputEvent subclasses (KeyEvent and MouseEvent) implement this method:
public long getWhen()
Returns the timestamp of when this event occurred.
For examples, see a text book, or the sites at the start of this document. Briefly, you create a class which implements one of the listener interfaces listed above. Important listener interfaces for the components mention in this objective are, for example: MouseListener, FocusListener, KeyListener or TextListener
Create suitable methods for the events you are interested, for the rest of the methods in the interface, just create an empty method body. For example, if you have a button, and you just need it to respond to being clicked, in your listener class you would put code in the mouseClicked() method, and implement the rest of the methods with empty bodies.
Then create an instance of the listener class and add it to the component in question using the components appropriate add method, which is the last column in the table above.
The argument types are listed in the "Listener Interfaces" table above, under the "Event" heading. The return type for all methods of all listener interface methods is void.
Section Title: The java.awt.package - Painting
The paint() method has the following signature:
public void paint(Graphics g) { }
Section Title: The java.io package
[Sun Certified Programmer for the Java™ 2 Platform
In spite of its omission in the objectives, Input/Output does come up in the examination, so needs to be learned by anyone taking the Java 2 exam, as well as anyone taking the 1.1 exam.]
For this section, you may find the following tables useful. They list the various kinds of Streams and Readers/Writers, along with what they "connect to", typically their constructor arguments.
Low Level Streams
Input Streams |
Arguments |
Output Streams |
Arguments |
FileInputStream |
File |
FileOutputStream |
File |
ByteArrayInputStream |
byte[] |
ByteArrayOutputStream |
Creates an array |
High Level Streams
Input Streams |
Arguments |
Output Streams |
Arguments |
FilterInputStream |
InputStream |
FilterOutputStream |
OutputStream |
DataInputStream Implements DataInput |
InputStream |
DataOutputStream Implements DataOutput |
OutputStream |
BufferedInputStream |
InputStream |
BufferedOutputStream |
OutputStream |
Low-level Readers/Writers
Readers |
Arguments |
Writers |
Arguments |
FileReader |
File |
FileWriter |
File |
CharArrayReader |
char[] |
CharArrayWriter |
Creates an array of chars |
StringReader |
String |
StringWriter |
Creates a String |
High-level Readers/Writers
Readers |
Arguments |
Writers |
Arguments |
BufferedReader |
Reader |
BufferedWriter |
Writer |
InputStreamReader |
InputStream |
OutputStreamWriter |
OutputStream |
String[] list() Returns a list (an array of Strings) of the files in the directory specified by this File
object.
length() Returns the length of the file represented by this File
object.
File
object to have the pathname given by the File
argument.
The following constructor for InputStreamReader allows you to specify the encoding scheme: InputStreamReader(InputStream in, String enc)
- in
- An InputStream
- enc
- Name of encoding to be used
Encoding scheme string "8859_1" is ASCII.
The constructor for OutputStreamWriter is similar, but the first argument is an OutputStream, obviously.
Readers (such as InputStreamReader) have the following methods for reading characters:
read
() -Read a single character.
read
(char[] cbuf) -Read characters into an array.
read
(char[] cbuf, int off, int len) -Read characters into a portion of an array.
Writers (such as OutputStreamWriter) have the following methods for writing characters:
write
(char[] cbuf)
-Write an array of characters.
write
(char[] cbuf, int off, int len) -Write a portion of an array of characters.
write
(int c) -Write a single character.
write
(String str) -Write a string.
write
(String str, int off, int len)
-Write a portion of a string.
To avoid corruption, text should be read using the same encoding scheme that it was written with. Therefore, in general platform default encoding may be used if the data is written on the same computer as it is going to be read. However if the text is going to be sent from one computer to another across a network, or if a text file is created on a different computer (for example files that are installed as part of an application), then a specific encoding scheme should be used at both ends.
The correct constructor argument for FilterInputStream is an instance of a subclass of InputStream. Similarily, the correct constructor argument for FilterOutputStream is an instance of a subclass of OutputStream.
FileInputStream and FileOutputStream, are described in the accompanying I/O tables.
RandomAccessFile is not part of the i/o stream or reader/writer hierarchies. The constructors are:
RandomAccessFile(String file, String mode)
RandomAccessFile(File file, String mode)
Important: For the RandomAccessFile constructor, the mode argument must either be equal to "r"
or "rw"
. Do not be fooled in the exam by credible sounding, but non-existent options like "r+w" or "w".
RandomAccessFile has a pointer which determines where to read/write in the file. getFilePointer() returns the current position in the file, in bytes, and seek(long position) sets the pointer to a specific location. There is also a length() method. This class implements the DataOutput and DataInput interfaces, which are described in the accompanying I/O tables.
RandomAccessFile will create an empty file if it is constructed as "rw". Constructing a FileOutputStream can create an empty file.
FileInputStream of course, never causes a file to be created or modified.
Section Title: The Applets & HTML
While this section is not listed in the objectives for the 1.1 or Java2 Platform (1.2) exams, it does come up in the exam.
Applets: Applet is a subclass of Panel, which is a subclass of Container. For information, here is a list of methods which are commonly overridden when creating your own applet:
init()
Called when applet is first instantiated.start()
Called when the web page containing the applet is about to (re-)appearstop()
Called when the web browser is about to move to another web pagerepaint()
Inherited from Componentupdate()
Inherited from Componentpaint()
Inherited from Component
Required HTML:
This is an example of the minimum HTML required to display an applet in a web page:
<APPLET CODE=MyProgram.class WIDTH=200 HEIGHT=400>
</APPLET>
HTML tags are not case-sensitive.
Passing parameters:
PARAM
: This allows you to pass a value to an applet. The tag looks like this:<PARAM NAME=message VALUE="Hello, World">
This tag is placed between "<APPLET …>" and "</APPLET>". The value is a string, and must be in quotes if it contains any spaces. To use these values in your applet, use the getParameter(String paramname ) method, which returns a string e.g.
String greeting;
greeting=getParameter("message");
The argument for this method is not case-sensitive so for example getParameter("mEsSaGE")would work just as well.
Sun Certified Programmer for the Java™ 2 Platform
Section Title: The java.util package
As far as I can gather, and this is implied by the objective itself and the sample examination question on the Sun website, this objective just requires a general knowledge of the classes/interfaces, in other words which to use for a given purpose. If you want a more in-depth treatment of the subject, try the Sun tutorial: http://java.sun.com/docs/books/tutorial/collections/index.html
Set
Implementations: Hashset
A Set is a collection which cannot contain any duplicate elements and has no explicit order to its elements (unlike, for example, an array, where every element exists at a particular index i.e. MyArray[15]).
SortedSet
Implementations: TreeSet
A SortedSet is a Set which maintains its elements in ascending order.
List
Implementations: LinkedList, ArrayList, Vector, Stack
A List is a collection which can contain duplicate elements, and the elements are ordered (like an array, you can add an element at a specific position, and the elements are accessed using their index).
[Stack has come up in the examination, so here is some info. on it.
Stack is a subset of Vector, which contains some extra methods. The idea of a stack is like its name, it acts like a piled up stack of items: When you add an element, it goes to the top of the stack, and when you extract an element, it is taken off the top. In other words, this is a last-in, first-out system. The methods are:
push(object)
- Add an element onto the top of the stack.pop()
- Removes the object at the top of this stack and returns that object as the value of this function.peek()
- Looks at (i.e. returns) the object at the top of this stack without removing it from the stack.. ]
Map
Implementations: HashMap, Hashtable, WeakHashMap
Maps keys to values. In other words, for every key, there is a corresponding value, and you look up the values using the keys. Maps cannot have duplicate keys, and each key maps to at most one value.
Note: A Map does not implement the Collection interface.
SortedMap
Implementations: TreeMap
A SortedSet is a Set which maintains its mapping in ascending key order.
Object Ordering
Implementations of the SortedSet and SortedMap interfaces sort their elements. To determine what criterion is used to sort the elements you can use either the Comparable or Comparator interfaces. Using Comparable means that the classes that you put in your SortedSet or SortedMap implement the Comparable interface, which just means that they contain a method compareTo() which determines whether the object is "greater" or "less than" another object. To use the Comparator interface, you pass an object which implements Comparator to your SortSet or Sorted map, and it will use the Comparator for ordering.
BitSet
For completeness, here is some information on BitSet, which isn't part of the Collections Framework, but may be examinable. A BitSet contains elements which are bits, i.e. of the boolean primitive type. Like, for example, a Vector, and unlike an array, a BitSet does not have a fixed size, and grows as needed when you add elements to it.