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.
This version is written according to the objectives of the "Sun Certified Programmer For Java™ 2 Platform 1.4" exam. For those taking the 1.2 exam, the objectives no longer required for 1.4 have been retained towards the end of this document. The sections have "1.2 Exam Only" at the start of their titles. I would recommend doing the 1.4 exam instead, as it is more current and the only major new subject is assertions.
Aside: There is no 1.3 exam, as such. The 1.1 exam exam was replaced by a Java2 exam, which at the time seemed like it would suffice for all Java2 releases. However in September 2002 Sun released seperate 1.2 and 1.4 exams. The 1.2 syllabus is for 1.2 and 1.3.
Thank you to everyone who has emailed me with compliments and/or corrections for previous versions of this document, it is appreciated. On the other hand, if you have questions on the exam or Java, I am afraid I do not have time to answer all of these, so please try either the certification discussion groups on the web, or the Java newsgroups.
Having obtained my certification, I have neither time or reason to maintain this document in the future and keep it current with changes in the exam. Rather than let it stagnate, I have decided to release it as a resource to the Java certification community under the Free Documentation License. This will allow others to change, correct, expand and update it. The accompanying XML file has more information on how to do this.
If you are just starting to prepare for the exam, then I recommend the following steps:
Suns own certification site, has FAQs, objectives and sample questions: http://suned.sun.com/US/certification/java/java_progj2se.html
Marcus Greens Site has exams, FAQs, tutorials:http://www.jchq.net/
A discussion forum: http://groups.yahoo.com/group/javacertstudy/
The JavaRanch, has a nice rules exam, and lots of cows: http://www.javaranch.com/
More links: http://directory.google.com/Top/Computers/Programming/Languages/Java/Resources/Certification/
Here are just a few comments on the exam itself. Firstly, time should not be a problem, as you should have time to answer all the questions, review them, and possibly be able to leave early. It will really be an issue of whether you know/understand what is required. That said, as with any exam, do not get bogged down in any one question, mark it and come back to it later if it is taking too long.
Generally, the questions in the real exam are a lot better than the mock exams which are going around: They less ambiguously 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 syntax rather than its APIs. Of course, you do need to be familiar with the APIs mentioned in the objectives to get a pass mark.
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 "1.2 Exam Only" sections are based on a subset of the 1.1 objectives with additions where needed, as they were taken from an older version of this document. This may seem strange but they provide good information for the 1.2 exam. At the time, the objectives for the Java 1.1 exam were more detailed and descriptive than those for the Java 2 exam, but the exams were very similar. I took the 1.2 exam (it was called just "Sun Certified Programmer For Java™ 2 Platform" at the time) in 1999, and released the first version of this document afterwards.
Write code that declares, constructs and initializes arrays of any base type using any of the permitted forms both for declaration and for initialization. |
For example,use either
int[] x;
or
int x[];
Both are legal positions for the brackets. To declare a multidimensional array, use multiple sets of brackets,
e.g. int i[][];
declares a two dimensional array. Note that, for example, int[]i[];
is also
legal, and means the same thing.
In Java, multidimensional arrays can be "not square" i.e. they are just arrays of arrays, and each of those constituent
arrays can be of a different size.
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];
The size of the array is in the brackets (in this example 10). It is common to do both operations in one statement:
int i[] = new int[10];
An example:
int array[] = new int[15]; for(int j=0; j<array.length;j++){ array[j]=j; }
An example:
char c[]= new char[] {'a','b','c','d','e'};
or you can use
char c[]= {'a','b','c','d','e'};
This is fundamental Java. If you are unsure of this topic, see a textbook.
A good but technical reference for these kinds of issues is the Java Language Specification (not for beginners).
It is available at the following URL:
http://java.sun.com/docs/books/jls/html/index.html
Scope/Visibility: Where something can be seen / is accessable from.
Nested/Inner Class: A class whose code sits inside the body of another 'outer' class. It exists 'inside' the class in that it can see the private methods and variables.
Instance/Member: Means the method/variable/nested class belongs to each object which is an instance of the class. The term 'a member' is often used to refer to both methods and variables of this type. Cannot be accessed by statically i.e. without having an instance of the class.
Class/Static: The method/variable/nested class belongs to the class as opposed to the instances of the class. Can be used without creating an instance of the class, but static methods/nested class cannot use instancts variables/methods.
Local/Automatic variable: A variable which is declared within a method or as a parameter to the method. Cannot be seen outside the method.
"default" or "friendly" - this is where no modifier is used. Means something is only visible to classes in the same package.
protected
- can only be accessed by classes in the same package or subclasses of this class.
This frequently surprises experienced developers, especially those with a prior backround in the mutant hybrid of object
orientated programming and assembly language known as 'C++' :-)
To fair the name is misleading, as it sounds like it restricts access, where as it in fact it adds subclasses outside
the package to the list of things that can access the item in question, as compared to using "default" access.
public
- can be accessed by any other class.
private
- can only be accessed from inside the class.
public
, abstract
or final
:
public
- is visible outside of its package. Without this modifier, the class cannot be accessed outside
its package.
abstract
- cannot be instantiated, is allowed to contain abstract
methods.
final
- cannot be subsclassed.
private
, protected
, public
, static
,
final
, native
or abstract
:
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 within the methodd
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.
Since Java1.1 you can declare the variable without assigning a value. Once you assign a value, you cannot change it. The are
known as
'blank' finals, are frequently used for things like constants you wish to initialise from a configuration file.
native
- a method which is not written in java and is outside the JVM in a library.
abstract
- a method which is not implemented. Must be implemented in a subclass if that subclass is to be
'concrete' and allow people to instantiate it.
Place the class definition (for the nested class) inside another class definition (the outer class) or a method.
An anonymous nested class is defined where is it instantiated (in a method). An anonymous nested 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 nested class:
return new SomeClass() { /*body of the anonymous class goes here*/ };
You might like to think of an anonymous nested class as part of a really long new
statement, which happens to
contain a class definition, and which is why it has a ";" at the end.
The following example calls someMethod()
, passing an instance of the anonymous nested class:
someMethod(new SomeClass() { /*body of the anonymous class goes here*/ });
In both cases SomeClass()
is not the name of the anonymous class (anonymous means it has no name) rather is it the name of
the class that you are extending or the interface you are implementing.
These classes cannot define a constructor, as they do not have a name that you can use to declare the constructor method.
If SomeClass()
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 SomeClass(12) { /*body of the anonymous class goes here*/ };
will call the SomeClass constructor which takes an int.
Inner x = new Inner();
constructs an instance of Inner where Inner is a nested class defined in the current class.
this
object exists,
or the current this
object is not an instance of the outer class.
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. 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.
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
, in addition to the above.
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).
For a given class, determine if a default constructor will be created and if so state the prototype of that constructor. |
The 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 using super(...)
(to use a constructor in the parent) or this(...)
.
If you use such calls, they must be the first thing in the constructor.
Write code using if , and switch statements and identify legal argument types for these
statements.
|
Consult a text book for the basics of these, if unsure. If you do know the basics, here are a few 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 and is
the best practice if you want readable code that is not potentially misleading. 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");
A good practice is to use blocks with all your if
and else
statements to avoid this ambiguity.
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) { case 1: System.out.println("one"); case 2: System.out.println("two"); case 3: System.out.println("three"); default: 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 might desirable, but here it isn't. This block of code fixes it:
switch (a) { case 1: System.out.println("one"); break; case 2: System.out.println("two"); break; case 3: System.out.println("three"); break; default: 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.
Number 3
The argument for an if()
statement must be a boolean or an expression which evaluates to a boolean. A common
beginners mistake is to use a single =
rather than ==
to compare values. The following gives a compiler
error:
public static void main(String[] args) { int a=1; 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.
Write code using all forms of loops including labeled and unlabeled, use of break and continue, and state the values taken by loop counter variables during and after loop execution. |
An loop example:
for(int i=0;i<3;i++){ System.out.println("i is "+i); for(int j=0;j<3;j++) { System.out.println("j is"+j); } }
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.
Labels are a name followed by a colon, i.e. ":", placed before the loop.
Write code that makes proper use of exceptions and exception handling clauses (try , catch() ,
finally ) and
declares methods and overriding methods that throw exceptions.
|
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 general 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.
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 was not designed 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();
If an exception is thrown, then the rest of the code in the try block is not executed. If any catch block matches the exceptions class or a super class of the exception, that block executes. If the exception is not caught correctly, then after the finally block executes, the rest of the code in the method is not executed.
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.
It is legal to have a try
block, followed by a finally
block, without any catch blocks.
One thing (probably not important for the exam) which could stop a finally clause from executing, is a call to
System.exit(0)
.
RuntimeExceptions
differ from normal exceptions in that they are not required to be declared or handled within a try block.
An Error
indicates serious problems that a reasonable application should not try to catch. Examples are the
VM running out of memory.
Write code that makes proper use of assertions, and distinguish appropriate from inappropriate uses of assertions. |
For more information see: http://java.sun.com/j2se/1.4/docs/guide/lang/assert.html.
The simplest form of assertion consists of the assert
keyword followed by an expression which evaluates to a boolean.
Example:
assert someObject != null;If the expression evaluates to
false
then an AssertionError
is thrown.
The other form adds a colon followed by a second expression which evaluates to a value of some kind.
If the assertion fails, the value is included in the AssertionError
for information.
Example:
assert someObject != null : "someObject should not be null at this point!";
Identify correct statements about the assertion mechanism. |
See the previous objective, or look in a textbook or on the web.
State the behavior that is guaranteed by the garbage collection system. |
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. At that stage, no variable points to the object, therefore your code has no way of accessing it and the object can safely be removed by the system.
Finalize Method
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
. Do not confuse the finalize()
method (garbage collection)
with the finally
keyword (exception handling).
Write code that explicitly makes objects eligible for garbage collection. |
My definition of explicit differs, as I would categorize this as implicit:
Date d = new Date(); d = null;There is no longer a reference pointing to the Date created on the first line, therefore that object is eligible for garbage collection. No matter what you do, there is no way your code could get back a reference to that object, so your code cannot be affect by its removal. If on the other hand you had passed the object into a Collection, or it was pointed to by some class, instance or local variable somewhere, then it is not ready for garbage collection (for example you could pass it to a method or constructor before setting d to null).
Date d = new Date(); d = new Date(0);The new Date created on the second line holds the value midnight, January 1, 1970. The previous object referred to by
d
, which held the current Date
is now eligable for garbage collection,
but the new value of d
(1/1/1970) is unaffected.
Recognize the point in a piece of source code at which an object becomes eligible for garbage collection. |
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 null
or a different object, so there is nothing
pointing to the original object. Or when a method exits, all the local 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.
package
declarations, import
statements,
public class declarations
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. }
main()
method.
[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 called 'main' in a class (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 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 static, not return a value, and take an array of strings.
Whether it is declared public is something of a controversy. The Java Language Specification clearly states "The method main
must be
declared public, static, and void. It must accept a single argument that is an array of strings."
On the other hand, 'The Complete Java2 Certification Study Guide' by Roberts, Heller et al. states. "The main method is declared
public by convention. However, it is a requirement that it be static...".
Tests indicate that in Java 1.2 (and 1.3), you can execute a program whose main()
method is private
, as
bizarre as that may seem. You cannot do this in Java 1.1. or in Java 1.4.1.
Exam candidates should follow the Java language specification, and assume public is required, as far as answering questions
is
concerned. Use the signature described below, in your code and in your exam answers.
Either of the following two examples are accepted ways of declaring main:
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.
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.
State the correspondence between index values in the argument array passed to a main method and command line arguments. |
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. The first command line argument is at position 0 in the array, the second at 1 etc. The java command and its various settings are not included in the list.
Identify classes that correctly implement an interface where that interface is either java.lang.Runnable or a fully
specified interface in the question.
|
There is only one method in the interface, run(), which must be implemented in the class.
public void run() { //Do something }
Identify all Java programming language keywords. Note: There will not be any questions regarding esoteric distinctions between keywords and manifest constants. |
Java keywords (check that you know what each of these does, if not, find out before you take the exam!):
abstract | assert | boolean | break | byte |
case | catch | char | class | const |
continue | default | do | double | else |
extends | final | finally | float | for |
goto | if | implements | import | instanceof |
int | interface | long | native | new |
package | private | protected | public | return |
short | static | strictFP | super | switch |
synchronized | this | throw | throws | transient |
try | void | volatile | while |
The keywords goto
and const
are reserved but not used.
While they are not keywords, the boolean and null literals (true
, false
and null
)
cannot be used as identifiers.
So fear ye not the "manifest constants" mentioned in the objective.
[Note that Roberts & Heller lists these as keywords, but they are literals, not keywords]
A new keyword in Java2 is strictFP
. strictFP
is not in versions of Java prior to Java2.
It is included here for completeness, however, I cannot say whether it is examinable and you
will have to look elsewhere for information on its syntax. This modifier tells the compiler to use a strict form of floating
point calculations, which ensures an identical result on every platform. In Java 1.1, this strict form is always used, but
in
Java2, when you don't specify strictFP, the Java virtual machine can do a fast calculation, which makes the most of the performance
of the native processor without the overhead of converting to a consistent cross-platform format.
[Technical aside, for those interested in microprocessors:
I believe part of the reason for its introduction is that the X86 CPUs have an 80bit FPU, versus 64bits used in the Java standard
and on Suns processors. Intel complained that this gave their CPUs a disadvantage in Java]
assert
is new to 1.4 - covered elsewhere in this document.
A brief note on some of the more obscure keywords:
transient
- indicates a field should not be serialized when the class is serialized.volatile
- indicates the field may be changed frequently by different threads. Somewhat like a weak form of synchronization.
State the effect of using a variable or array element of any kind when no explicit assignment has been made to it. |
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, '\u0000'
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 (local variables) to some value, you will get a compiler error.
State the range of all primitive formats, data types and declare literal values for String and all primitive types using all permitted formats bases and representations. |
A guide to understanding the ranges is to remember that if a type is x bits in size, then it can hold 2x possible
combinations of bits.
0 must be represented somehow, so that is why 1 is subtracted from the maximum value. Negative values must be represented,
so you
must take one
away from the exponent. For example, a byte
is 8 bit (28), but one bit is needed for the positive/negative,
so the exponent is 7 (-27 to 27).
Then we subtract one for zero, giving -27 to 27-1.
chars
are an exception as they are unsigned, so there are no negative values. floats
and
doubles
are more complex. They use some
bits to store the binary digits and others to store the exponent, like a binary version of scientific notation (e.g. 1.2354*105).
It is unlikely you will be required to know these for the exam.
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 263-1 |
char | 16 bit | '\u0000' to '\uffff' (0 to 216-1 )
|
float | 32 bit | Max. positive value: (2-2-23)*2127. Min. positive value: 2-149 |
double | 64 bit | Max. positive value: (2-2-52)*21023. Min. positive value: 2-1074 |
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
values using quoted format.
String duh = "This should be obvious, but I'll include an example anyway.";
char
type using Java's unicode escape format for a specified character code.
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.
Determine the result of applying any operator (including assignment operators and instance of) to operands of any type class scope or accessibility or any combination of these. |
Most of the operators are fundamental Java, so consult a textbook or tutorial if you are unsure of them. Here is information on some them, and notes on promotion rules.
'>>'
, '>>>'
and '<<'
operators to an int
value specified as a bit pattern.
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 fills in 0s on the right).
+
operator
Adds. If any of the variables are Strings, it converts the non-Strings to Strings, and concatenates (joins) them.
'=='
comparison operator with two objects of any type.
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
.
This consists of a boolean expression, followed by question mark, then two expressions, seperated from each other by a colon.
If the
boolean expression before the question mark evaluates as true
, the value from the expression before the colon is used,
otherwise the value from the last expression is used.
Example:
int a = true ? 1 : 0; int b = false ? 1 : 0;
a
will be 1. b
will be 0.
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").
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.
This has import consequences. For example:
byte b = 3; b = b + 5;will not compile, because the result of b+5 is an int.
Determine the result of applying the boolean equals() (Object) method to objects of any combination of the classes
java.lang.String , java.lang.Boolean , and java.lang.Object .
|
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.
In an expression involving the operators & , | , && and || ,
state which operands are evaluated and determine the resulting value of the expression.
|
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.
Determine the effect upon objects and primitive values of passing variables into methods and performing assignments or other modifying operations in that method. |
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. 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.
Note that primitive variables, in the calling method, are unaffected by modifications made in the target method. This is called passing by value. Look at this code:
void methodA() { int x=5; methodB(x); System.out.println(x); } void methodB(int x) { int x=10; }If you execute
methodA()
, it will print out "5". This is because it is the value of the variable x
(which is 5), that is passed to methodB()
. methodB()
accepts this value into a local variable, which is
coincidentally named x
aswell. But it is a different variable. Subsequent changes inside methodB()
will
not change the value of x
in methodA()
.
Price
class just stores the value assigned to it (using its constructor) as a member variable.
The toString()
method has been overwritten to return this value. It also has a setPrice()
method to change
its value.
void methodA() { Price x = new Price(5); methodB(x); System.out.println(x); } void methodB(Price x) { Price x = new Price(10); }This example, just like the one above, will print out "5". Note that the value being passed here to
methodB()
is in reality the location of the Price object in memory.
In methodB()
, the local variable x
is re-assigned to point to a new Price object, but what
methodA()
sees is unaffected.
This is made obvious here by the use of the new
keyword.
On the other hand, if you do operations which modify the object in the target methods, those changes will be visible in the
calling
method, as in the following example:
void methodA() { Price x = new Price(5); methodB(x); System.out.println(x); } void methodB(Price x) { x.setPrice(10); }This will print out "10". Again
methodB()
is passed the location of the Price object, which it holds in a local
variable x. However, when you call the setPrice()
method, this change goes out to the actual object in memory,
and hence methodA()
sees the same new value, 10.
State the benefits of encapsulation in object oriented design and write code that implements tightly encapsulated classes and the relationships "is a" and "has a". |
Encapsulation is the principal of keeping the internal details of a classes state and behaviours hidden from the other classes that use it. This allows you to change those details where necessary, without breaking compatibility. The interconnectness between pieces of code is called 'coupling', and minimising it makes for more reusable and maintainable classes. The expectated behaviour of a class or method is referred to as its 'contract'. You do not want to expose any more than the minimum required to support the contract, or you can end up with tangled interdependent code with poor maintainabilty, and in all likelyhood, poor quality.
Encapsulation also aids polymorphism and inheritance - if the internal details of a class are exposed and used, it is very hard to substitute a different implementation of the same contract.
To achieve good encapsulation, make everything have the tightest possible access control so if something should not be used in a given context, limit the access to prohibit it. In particular, class instance variables should be private, and accessed only through 'get'/'set' methods (a.k.a accessors and mutators). This would allow you to do some work or checking before reading/writing a value to the variable. You could remove the variable entirely and derive it or obtain it from another source. If the variable was public, and was accessed directly, should changes would break client code.
Briefly, 'is a' should be implemented using inheritance, 'has a' should be implemented using containment (i.e. 'composition' or sometimes 'aggregation'). This objective is conceptual, consult a textbook for more.
Determine at run time if an object is an instance of a specified class or some subclass of that class using the instanceof operator.
|
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
.
Write code to invoke overridden or overloaded methods and parental or overloaded constructors; and describe the effect of invoking these methods. |
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. This is called the methods signature. 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 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.
A related point is that you cannot override variables or static
methods, rather you hide
them when you declare, in a subclass, a variable of the same name or static method with the same signature. This is one of
these things
that occasionally surprises experienced developers. It is an important distinction as the polymorphic behaviour which happens
when overriding (see below) does not apply here.
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 invoked. Look at this example:
class Animal { void sayHello() { System.out.println("Hello, I'm an animal."); } } class Dog extends Animal { void sayHello() { System.out.println("Hello, I'm a dog."); } }
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 it is the class of the reference that matters, rather than that of the underlying object.
super
.
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 hierarchy.
Write code to construct instances of any concrete class including normal top level classes and nested classes. |
This is fairly straight forward, just use the new
operator. Nested classes are covered in another section.
this()
and super()
to access overloaded or parent-class constructors.
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 (and there may not be a default constructor in the 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.
Write code to define, instantiate and start new threads using both java.lang.Thread and java.lang.Runnable. |
To define a class that implements Runnable, you must define a run()
method in the class e.g.
class MyClass implements Runnable { public void run () { // Insert the code you want to run in a thread here } }
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 { public void run () { // 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(); mt.start();
Recognize conditions that might prevent a thread from executing. |
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)
wait()
method. This method called can only be made in a
synchronized
method or block. A later call in the synchronized
code to notify()
tells the thread (or notifyAll()
tells all the threads waiting on this object) the lock for this object has
become available, and when the method obtains the lock on the monitor, it goes into the Ready state.
sleep()
method puts the thread into a Sleeping state for a specified amount of time, after which it enters
a Ready state. sleep(long milliseconds)
or sleep(long milliseconds int nanoseconds)
. This method
throws InterruptedException.
suspend()
method. It will go back to a Ready state when
its resume()
method is called by another thread.run()
method has completed (the thread can never be restarted)
Write code using synchronized wait, notify and notifyAll to protect against concurrent access problems and to communicate between threads. |
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.
This is a complicated area, if it is new to you, consult a textbook.
synchronized
keyword to require a thread of execution to obtain an object lock prior to proceeding.
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) { // synchronized code } // more code...
wait()
method.
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()
or notifyAll()
methods of an object.
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.
Define the interaction among threads and object locks when executing synchronized wait, notify or notifyAll. |
Consult a textbook or the web.
Write code using the following methods of the java.lang.Math class: abs() , ceil() ,
floor() , max() , min() , random() , round() , sin() ,
cos() , tan() , sqrt() .
|
See the JavaDocs for more detail.
abs()
- Returns the absolute value of the argument. Overloaded for ints
, longs
,
floats
and doubles
.
ceil(double)
- Returns the smallest (closest to negative infinity) 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 between 0.0
and 1.0
.
round(double)
- Returns the closest long
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.
Describe the significance of the immutability of String objects.
|
String objects cannot be changed. They are assigned a sequence of characters when they are constructed. Look at the following code:
String message = "Good"; message= message + " morning";
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 existing 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.
There are two fundamental types of variables in Java: primitives and objects. Sometimes a method or a constructor takes objects,
but what
what you have is a primitive. To cope with this situation, Java has a set of 'wrapper' classes which exist to hold the value
of a primitive.
For example, you might want to use a float
as a key in a Map e.g. keying some business objects representing a loan by their
respective interest rates. Using the Float class will allow you to do this. You would create a Float object for each value,
and place that
object into the Map.
Primitive Type | Corresponding Wrapper class |
boolean | Boolean |
byte | Byte |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
The names are entirely obvious, except for the two that have been highlighted. Take a look at these classes in the JavaDocs. The pattern tends to be pretty similar: For a primitive type x, there is one constructor taking x and another that takes a String, which is parsed to get the value. There is a static parseX() method, which parses a string and returns the primitive type x. An xValue() method returns the underlying primitive value held by wrapped object. The toString() method from Object is overridden appropriately.
toHexString()
is a static method on Integer and Long which creates a hexadecimal string representation of the
argument as an unsigned integer in base 16.
Make appropriate selection of collection classes/interfaces to suit specified behavior requirements. |
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
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.
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 in the past, 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.. ]
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 SortedSet 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.
Distinguish between correct and incorrect implementations of hashcode methods. |
The hashcode value of an object gives a number which can be used to in effect to 'index' objects in a collection.
A collection class can group its objects by their hashcodes, and if you called e.g. contains()
(or get()
in
case of a Map), it can first
find the group based on the hashcode, then search that group. This avoids the need to check every object in the collection.
The requirements of a hashCode()
implementation are that if two objects are equal as determined the equals()
method, their hashcodes should be the same. This is why wherever you override the equals()
method, you should
override hashCode()
aswell.
The reverse is not required i.e. it is permitted for two objects that are not equal to have the same hashcode. This makes
sense, as
it is not always possible to ensure unique hashCodes. The method returns an int
and there are only an finite number
of int
values to use. However, where possible, it is desirable to have the hashcodes be distinct as this can improve
performance. If the hashcodes can be well distributed (i.e. scattered throughtout the int
range) aswell, all the better.
Write code to demonstrate the use of the following methods of the java.awt.Component class:
setVisible(boolean) , setEnabled(boolean) , getSize() , setForeground()
and setBackground() .
|
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.
Construct a java.awt.TextArea or java.awt.List that prefers to display a specified number of
columns.
|
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)
Creates a new scrolling list initialized with the specified number of visible lines. By default, multiple selections are not allowed.
List(int rows, boolean multipleMode)
Creates a new scrolling list initialized to display the specified number of rows. If the value ofmultipleMode
istrue
, then the user can select multiple items from the list. If it isfalse
, only one item at a time can be selected.
The constructors for a TextArea are under the next objective.
Construct a java.awt.TextArea or java.awt.TextField that prefers to display a specified
number of columns.
|
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)
Constructs a new empty TextArea with the specified number of rows and columns.
TextArea(String text, int rows, int columns)
Constructs a new text area with the specified text, and with the specified number of rows and columns. This text area is created with both vertical and horizontal scroll bars.
Note: It is the number of rows, then columns. This is counter-intuitive, as usually in programming you specify a horizontal dimension, then a vertical one, so this exception can catch you out.
A TextField
has a single line of text:
TextField(int columns)
Constructs a new empty TextField with the specified number of columns.
TextField(String text, int columns)
Constructs a new text field initialized with the specified text to be displayed, and wide enough to hold the specified number of characters.
State the significance of a "column" where one of the text components is using a proportional (variable) pitch font or a fixed pitch font. |
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.
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)
Adds the specified component to the end of this container. Also notifies the layout manager to add the component to this container's layout using the specified constraints object.
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.
Distinguish between AWT classes which are directly responsible for determining component layout and those which are responsible for implementing that layout. |
You set the layout manager that a container should use. That layout manger then implements the layout.
Write code to change the layout scheme associated with an AWT container. |
public void setLayout(LayoutManager mgr)
Sets the layout manager for this container.
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 windows, frames and dialogs. 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.
Use BorderLayout , FlowLayout , and GridLayout to achieve required
dynamic resizing behavior of a component.
|
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 described 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)
Constructs a new Flow Layout with the specified alignment and a default 5-unit horizontal and vertical gap. The value of the alignment argument must be one ofFlowLayout.LEFT
,FlowLayout.RIGHT
, orFlowLayout.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)
Creates a grid layout with the specified number of rows and columns. All components in the layout are given equal size. One, but not both, ofrows
andcols
can be zero, which means that any number of objects can be placed in a row or in a column.
Remember: it is rows, then columns. If the number of components added is more than the number of cells (i.e. rows * columns) then more columns are added as needed, but the number of rows remains the same.
public GridLayout()
Creates a grid layout with a default of one column per component, in a single row.
GridBagLayout
While it is not mentioned in the objectives, GridBagLayout is examined in SCJP 2.
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 fields 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 ofCENTER
(default),EAST
,WEST
,NORTH
,NORTHEAST
,NORTHWEST
,SOUTH
,SOUTHEAST
orSOUTHWEST
)
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 ofNONE
(Default),HORIZONTAL
,VERTICAL
, orBOTH
)
gridheight
Specifies the number of cells in a column for the component's display area.
UseREMAINDER
to specify that the component be the last one in its column. UseRELATIVE
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.
UseREMAINDER
to specify that the component be the last one in its row. UseRELATIVE
to specify that the component be the next-to-last one in its row.
[HereREMAINDER
acts somewhat like a carriage return. You add elements to the row, and when you useREMAINDER
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 constantRELATIVE
(which is the default) specifies that this component be placed next (i.e. to the right forgridx
, and below forgridy
) to the previously added component. The top left cell hasgridx=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)
Creates and initializes a new 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.
Write a non-abstract class that implements a specified Listener interface, given the interface definition. |
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() | addActionListener() |
AdjustmentListener | AdjustmentEvent | adjustmentValueChanged() | addAdjustmentListener() |
ComponentListener | ComponentEvent |
componentHidden() componentMoved() componentResized() componentShown() |
addComponentListener() |
ContainerListener | ContainerEvent |
componentAdded() componetRemoved() |
addContainerListener() |
FocusListener | FocusEvent |
focusGained() focusLost() |
addFocusListener() |
InputMethodListener | InputMethodEvent |
caretPositionChanged() inputMethodTextChanged() |
addInputMethodListener() |
ItemListener | ItemEvent | itemStateChanged() | addItemListener() |
KeyListener | KeyEvent |
keyPressed() keyReleased() keyTyped() |
addKeyListener() |
MouseListener | MouseEvent |
mouseClicked() mouseEntered() mouseExited() mousePressed() mouseReleased() |
addMouseListener() |
MouseMotionListener | MouseEvent |
mouseDragged() mouseMoved() |
addMouseMotionListener() |
TextListener | TextEvent | textValueChanged() | addTextListener() |
WindowListener | WindowEvent |
windowActivated() windowClosed() windowClosing() windowDeactivated() windowDeiconified() windowIconified() windowOpened() |
addWindowListener() |
Select methods from the classes in the java.awt.event package that identify the affected component, mouse position,
nature, and time of the event.
|
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()
Returns: the Component object that originated the event
All events implement this method:
public Object getSource()
Returns: the object on which the Event initially occurred.
Mouse Position:
MouseEvent implements these methods:
public Point getPoint()
Returns: a Point object containing the x and y coordinates relative to the source component
public int getX()
Returns: x an integer indicating horizontal position relative to the component
public int getY()
Returns: y an integer indicating vertical position relative to the component
Nature:
All AWTEvent subclasses implement this method:
public int getID()
Returns the event type. This can be compared with the event mask constants defined in the class for the different types of
event e.g. MOUSE_EVENT_MASK
.
Time:
InputEvent subclasses (KeyEvent and MouseEvent) implement this method:
public long getWhen()
Returns the timestamp of when this event occurred.
Demonstrate correct uses of the Listener methods in the Component , TextArea , and
TextField classes.
|
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 mentioned 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.
[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 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
.
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.
Input Streams | Arguments | Output Streams | Arguments |
FileInputStream | File | FileOutputStream | File |
ByteArrayInputStream | byte[] | ByteArrayOutputStream | (Creates an array) |
Input Streams | Arguments | Output Streams | Arguments |
FilterInputStream | InputStream | FilterOutputStream | OutputStream |
DataInputStream
Implements DataInput |
InputStream | DataOutputStream
Implements DataOutput |
OutputStream |
BufferedInputStream | InputStream | BufferedOutputStream | OutputStream |
Readers | Arguments | Writers | Arguments |
FileReader | File | FileWriter | File |
CharArrayReader | char[] | CharArrayWriter | Creates an array of chars |
StringReader | String | StringWriter | Creates a String |
Readers | Arguments | Writers | Arguments |
BufferedReader | Reader | BufferedWriter | Writer |
InputStreamReader | InputStream | OutputStreamWriter | OutputStream |
Write code that uses objects of the file class to navigate a file system. |
Methods that support navigation:
boolean exists()
- Tests if this File exists.
String getAbsolutePath()
- Returns the absolute pathname of the file represented by this object.
String getCanonicalPath()
- Returns the canonical form of this File object's pathname.
String getName()
- Returns the name of the file represented by this object.
String getParent()
- Returns the parent part of the pathname of this File object, or null if the name has no parent part.
String getPath()
- Returns the pathname of the file represented by this object.
boolean isDirectory()
- Tests if the file represented by this File object is a directory.
boolean isFile()
- Tests if the file represented by this File object is a "normal" file.
String[] list()
- Returns a list (an array of Strings) of the files in the directory specified by this
File
object.
Note: The File class does not provide a method to change the current working directory.
Other methods worth being aware of:
mkdir()
- Creates a directory whose pathname is specified by this File object.
delete()
- Deletes the file specified by this object.
length()
- Returns the length of the file represented by this File
object.
renameTo(File)
- Renames the file specified by this File
object to have the pathname given by the
File
argument.
canRead()
& canWrite()
- Return true
if the file is readable/writeable.
Write code that uses objects of the classes InputStreamReader and OutputStreamWriter to
translate between Unicode and either platform default or ISO 8859-1 character encodings.
|
The following constructor for InputStreamReader allows you to specify the encoding scheme:
InputStreamReader(InputStream in, String enc)
Create an InputStreamReader that uses the named character encoding.
Parameters:in
- An InputStreamenc
- 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.
Destinguish between conditions under which platform default encoding conversion should be used and conditions under which a specific conversion should be used. |
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.
Select valid constructor arguments for FilterInputStream and FilterOutputStream subclasses from a list of classes in the java.io.package. |
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.
Write appropriate code to read, write and update files using FileInputStream, FileOutputStream, and RandomAccessFile objects. |
See a textbook, the Java tutorials or Javadocs if you are unsure of this area. Here is some brief information on RandomAccessFile:
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 DataInput
and DataOutput
interfaces, which have read or write methods (respectively)
for all the primitives, strings, and byte arrays ( readFully
and write()
respectively). The
DataInput
interface also has skipBytes()
method. Consult the Java API Docs for more on these interfaces.
Describe the permanent effects on the file system of constructing and using FileInputStream, FileOutputStream, and RandomAccessFile objects. |
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.
length()
- Returns the length of this string.
toUpperCase()
- Converts this string to uppercase.
toLowerCase()
- Converts this String to lowercase.
[Note thattoLowerCase()
andtoUpperCase()
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. There appears to be a bug in Suns JDK 1.1 which causes this not to occur, but this is the behaviour described by the JavaDocs. Java2 behaves as described in the JavaDocs.]
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 from 0
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.
Parameters:
ch - a character.
fromIndex - the index to start the search from.
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.
Parameters:
ch - a character.
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 specified beginIndex
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, the toString
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 e.g. for debugging info. For the Strings,
toString()
returns the String object itself.
State all operators that are legal in String expressions.
|
The + operator
to concatenate strings.