Java2 Certification
|
|
You can discuss this topic with others at http://www.jchq.net/discus
Read reviews and buy a Java Certification book at http://www.jchq.net/bookreviews/jcertbooks.htm
Declare classes, inner classes, methods, instance variables static, variables and automatic (method local) variables, making appropriate use of all permitted modifiers (such as public final static abstract and so forth). State the significance of each of these modifiers both singly and in combination and state the effect of package relationships on declared items qualified by these modifiers.
I find it a little disturbing that the objective uses the words "and
so forth".
I suspect this means you should also be aware of
Because Java was designed to be easy for C++ programmers to learn there are
many similarities between the way the two languages deal with classes. Both
C++ and Java have inheritance, polymorphism, and data hiding using visibility
modifiers. Some of the ways in which they differ are to do with making Java
an easier language to learn and use.
The C++ language implements multiple inheritance and thus a class can have more
than one parent (or base) class. Java allows only single inheritance and thus
can only ever have a single parent. To overcome this limitation Java has a feature
called interfaces. The language designers decided that interfaces would give
some of the benefits of multiple inheritance without the drawbacks. All Java
classes are descendants of the great ancestor class called Object.
Objects in Visual Basic are somewhat of a bolt on afterthought to the language.
Visual Basic is sometimes called an Object Based language rather than Object
Oriented. It is almost as if the language designers decided that classes are
cool and with VB version 4 decided that they would create a new type of module,
call it a class and use the dot notation to make it more like C++. The crucial
element missing from the VB concept of class is that of inheritance. With VB5
Microsoft delivered the concept of interfaces which acts similarly to the Java
concept of an interface. Some of the main similarities between VB classes and
Java classes is the use of references and the keyword new word.
Classes are the heart of Java, all Java code occurs within a class. There is no concept of free standing code and even the most simple HelloWorld application involves the creation of a class. To indicate that a class is a descendent of another class the extends keyword is used. If the extends keyword is not used the class will be a descended of the base class Object, which gives it some basic functionality including the ability to print out its name and some of the capability required in threads.
The minimum requirements to define a class are the keyword class, the class name and the opening and closing braces. Thus
class classname {}
is a syntactically correct, if not particularly useful class (surprisingly I have found myself defining classes like this, when creating examples to illustrate inheritance).
Normally a class will also include an access specifier before the keyword class and of course, a body between the braces. Thus this is a more sensible template for a class.
public class classname{
//Class body goes here
}
Here is a simple HelloWorld program that will output the string "hello world" to the console.
public class HelloWorld{ public static void main(String argv[]){ System.out.println("Hello world"); } }//End class definition
The keyword public is a visibility modifier that indicates this class should be visible to any other class. Only one outer class per file can be declared public. Inner classes will be covered elsewhere. If you declare more than one class in a file to be public, a compile time error will occur. Note that Java is case sensitive in every respect. The file that contains this class must be called HelloWorld.Java. Of course this is somewhat of an anomaly on Microsoft platforms that preserve, yet ignore the case of letters in a file name.
The keyword class indicates that a class is about to be defined and HelloWorld is the name of that class. The curly braces indicate the start of the class. Note that the closing brace that ends the class definition does not involve any closing semi colon. The comment
//End class definition
uses the style of single line comments that is available in C/C++. Java also understands the multi-line /* */ form of comments.
Giving a method the following signature has a certain significance (or magic) as it indicates to Java that this is where the program should begin its run, (similar to main in the C language).
public static void main(String argv[]){
This line indicates that a method called main is being defined that
takes arguments (or parameters) of an array of Strings. This method is public,
i.e. visible from anywhere that can see this class. The static keyword
indicates that this method can be run without creating an instance of the
class. If that means nothing to you, don't worry about it for the moment as
static methods will be covered at length elsewhere. The keyword
void indicates the data type returned from this method when it is
called. The use of void indicates that no value will be returned.
The parameters of the main method
String argv[]
Indicate that the method takes an array of type String. The square brackets indicate an array. Note that the data type String starts with an upper case S. This is important as Java is thoroughly case sensitive. Without this exact signature the Java Virtual Machine will not recognise the method as the place to start execution of the program.
The HelloWorld application as described above is handy to illustrate the most basic of applications that you can create, but it misses out on one of the most crucial elements of using classes, the use of the key word
new
Which indicates the creation of a new instance of a class. In the HelloWorld application this was not necessary as the only method that was called was System.out.println, which is a static method and does not require the creation of a class using the new keyword. Static methods can only access static variables, of which only one instance can exist per class. The HelloWorld application can be slightly modified to illustrate the creation of a new instance of a class.
public class HelloWorld2{ public static void main(String argv[]){ HelloWorld2 hw = new HelloWorld2(); hw.amethod(); } public void amethod(){ System.out.println("Hello world"); } }
This code creates a new instance of itself with the line
HelloWorld2 hw = new HelloWorld2();
This syntax of creating a new instance of a class is basic to the use of classes. Note how the name of the class appears twice. The first time indicates the data type of the reference to the class. This need not be the same as the actual type of the class as indicated after the use of the new keyword. The name of this instance of the class is hw. This is simply a name chosen for a variable. There is a naming convention that an instance of a class starts with a lower case letter, whereas the definition of a class starts with an upper case letter.
The empty parenthesis for the name of the class HelloWorld() indicate that the class is being created without any parameters to its constructor. If you were creating an instance of a class that was initialized with a value or a string such as the label of a button the parenthesis would contain one or more initializing values.
As illustrated in the last example HelloWorld2, a method in Java is similar to a function in C/C++ and a function or sub in Visual Basic. The method called amethod in that example is the method called amethod in this example is declared as
public
To indicate it can be accessed from anywhere. It has a return type of
void
indicating no value will be returned. And it has empty parenthesis, indicating that it takes no parameters.
The same method might have been defined in these alternative ways
private void amethod(String s) private void amethod(int i, String s) protected void amethod(int i)
These examples are to illustrate some other typical signatures of methods. The use of the keywords private and protected will be covered elsewhere.
The difference between Java methods and methods in a non OO language such as C is that the methods belong to a class. This means they are called using the dot notation indicating the instance of the class that the code belongs to. (Static methods are an exception to this but don't worry about that at the moment).
Thus in HelloWorld2 amethod was called thus
HelloWorld hw = new HelloWorld() hw.amethod();
If other instances of the HelloWorld class had been created the method could have been called from each instance of the class. Each instance of the class would have access to its own variables. Thus the following would involve calling the amethod code from different instances of the class.
HelloWorld hw = new HelloWorld(); HelloWorld hw2 = new HelloWorld();
hw.amethod(); hw2.amethod();
The two instances of the class hw and hw2 might have access to different variables.
Automatic variables are method variables. They come into scope when the method code starts to execute and cease to exist once the method goes out of scope. As they are only visible within the method they are typically useful for temporary manipulation of data. If you want a value to persist between calls to a method then a variable needs to be created at class level.
An automatic variable will "shadow" a class level variable.
Thus the following code will print out 99 and not 10.
public class Shad{ public int iShad=10; public static void main(String argv[]){ Shad s = new Shad(); s.amethod(); }//End of main public void amethod(){ int iShad=99; System.out.println(iShad); }//End of amethod }
The visibility modifiers are part of the encapsulation mechanism for Java. Encapsulation allows separation of the interface from the implementation of methods. |
The visibility modifiers are a key part of the encapsulation mechanism for java. Encapsulation allows separation of the interface from the implementation of methods. The benefit of this is that the details of the code inside a class can be changed without it affecting other objects that use it. This is a key concept of the Object Oriented paradaigm (had to use that word somewhere eventually).
Encapsulation generally takes form of methods to retrieve and update the values of private class variables. These methods are known as a accessor and mutator methods. The accessor (or get) method retrieves the value and the mutator changes (or sets) the value. The naming convention for these methods are setFoo to change a variable and getFoo to obtain the contents of a variable. An aside note: the use of get and set in the naming of these methods is more significant than just programmer convenience and is an important part of the Javabeans system. Javabeans are not covered in the programmer exam however.
Take the example where you had a variable used to store the age of a student.
You might store it simply with a public integer variable
int iAge;
later when your application is delivered you find that some of your students have a recorded age of more than 200 years and some have an age of less than zero. You are asked to put in code to check for these error conditions. So wherever your programs change the age value, you write if statements that check for the range.
if(iAge > 70){ //do something } if (iAge <3){ //do something }
In the process of doing this you miss some code that used the iAge variable and you get called back because you have a 19 year old student who is on your records has being 190 years old.
The Object Oriented approach to this problem using encapsulation, is to create methods that access a private field containing the age value, with names like setAge and getAge. The setAge method might take an integer paramete and update the private value for Age and the getAge method would take no parameter but return the value from the private age field.
public void setAge(int iStudentAge){ iAge = iStudentAge; } public int getAge(){ return iAge; }
At first this seems a little pointless as the code seems to be a long way around something that could be done with simple variable manipulation. However when they come back to you with the requirement to do more and more validation on the iAge field you can do it all in these methods without affecting existing code that uses this information.
By this approach the implementation of code, (the actual lines of program code), can be changed whilst the way it looks to the outside world (the interface) remains the same.
Private variables are only visible from within the same class as they are created.in. This means they are NOT visible within sub classes. This allows a variable to be insulated from being modified by any methods except those in the current class. As described in modifiers and encapsulation, this is useful in separating the interface from the implementation.
class Base{ private int iEnc=10; public void setEnc(int iEncVal){ if(iEncVal < 1000){ iEnc=iEncVal; }else System.out.println("Enc value must be less than 1000"); //Or Perhaps thow an exception }//End if } public class Enc{ public static void main(String argv[]){ Base b = new Base(); b.setEnc(1001); }//End of main }
The public modifier can be applied to a variable (field) or a class. It is the first modifier you are likely to come across in learning Java. If you recall the code for the HelloWorld.Java program the class was declared as
public class HelloWorld
This is because the Java Virtual Machine only looks in a class declared as public for the magic main startup method
public static void main(String argv[])
A public class has global scope, and an instance can be created from anywhere within or outside of a program. Only one non inner class in any file can be defined with the public keyword. If you define more than one non inner class in a file with the keyword public the compiler will generate an error.
Using the public modifier with a variable makes it available from anywhere. It is used as follows,
public int myint =10;
If you want to create a variable that can be modified from anywhere you can declare it as public. You can then access it using the dot notation similar to that used when calling a method.
class Base { public int iNoEnc=77; }
public class NoEnc{ public static void main(String argv[]){ Base b = new Base(); b.iNoEnc=2; System.out.println(b.iNoEnc); }//End of main }
Note that this is not the generally suggested way as it allows no separation between the interface and implementation of code. If you decided to change the data type of iNoEnc, you would have to change the implementation of every part of the external code that modifies it.
The protected modifier is a slight oddity. A protected
variable is visible within a class, and in sub classes, the same package but
not elsewhere. The qualification that it is visible from the same package can
give more visibility than you might suspect. Any class in the same directory is
considered to be in the default package, and thus protected classes will be
visible. This means that a protected variable is more visible than a variable
defined with no access modifier.
A variable defined with no access modifier is said to have default visibility.
Default visibility means a variable can be seen within the class, and from
elsewhere within the same package, but not from sub-classes that are not in the
same package.
Static is not directly a visibility modifier, although in practice it does have this effect. The modifier static can be applied to an inner class, a method and a variable. Marking a variable as static indicates that only one copy will exist per class. This is in contrast with normal items where for instance with an integer variable a copy belongs to each instance of a class. Thus in the following example of a non static integer three instances of the integer iMyVal will exist and each instance can contain a different value.
class MyClass{ public int iMyVal=0; } public class NonStat{ public static void main(String argv[]){ MyClass m1 = new MyClass(); m1.iMyVal=1; MyClass m2 = new MyClass(); m2.iMyVal=2; MyClass m3 = new MyClass(); m3.iMyVal=99; //This will output 1 as each instance of the class //has its own copy of the value iMyVal System.out.println(m1.iMyVal); }//End of main }
The following example shows what happens when you have multiple instances of a
class containing a static integer.
class MyClass{ public static int iMyVal=0; }//End of MyClass public class Stat{ public static void main(String argv[]){ MyClass m1 = new MyClass(); m1.iMyVal=0; MyClass m2 = new MyClass(); m2.iMyVal=1; MyClass m3 = new MyClass(); m2.iMyVal=99; //Because iMyVal is static, there is only one //copy of it no matter how many instances //of the class are created /This code will //output a value of 99 System.out.println(m1.iMyVal); }//End of main }
Bear in mind that you cannot access non static variables from within a static method. Thus the following will cause a compile time error
public class St{ int i; public static void main(String argv[]){ i = i + 2;//Will cause compile time error } }
A static method cannot be overriden to be non static in a child class |
A static method cannot be overriden to be non static in a child class. There is no similar rule with reference to overloading. The following code will cause an error as it attempts to override the class amethod to be non-static.
class Base{ public static void amethod(){ } } public class Grimley extends Base{ public void amethod(){}//Causes a compile time error }
The IBM Jikes compiler produces the following error
Found 1 semantic error compiling "Grimley.java": 6. public void amethod(){} <-------> *** Error: The instance method "void amethod();" cannot override the static method "void amethod();" declared in type "Base"
The native modifier is used only for methods and indicates that the body of
the code is written in a language other than Java such as C and C++. Native
methods are often written for platform specific purposes such as accessing some
item of hardware that the Java Virtual Machine is not aware of. Another reason
is where greater performance is required.
A native method ends with a semicolon rather than a code block. Thus the
following would call an external routine, written perhaps in C++
public native fastcalc();
It is easy to overlook the abstract modifier and miss out on some of
its implications. It is the sort of modifier that the examiners like to ask
tricky questions about.
The abstract modifier can be applied to classes and methods. When applied
to a method it indicates that it will have no body (ie no curly brace part)
and the code can only be run when implemented in a child class. However there
are some restrictions on when and where you can have abstract methods
and rules on classes that contain them. A class must be declared as abstract
if it has one or more abstract methods or if it inherits abstract methods for
which it does not provide an implementation. The other circumstance when a class
must be declared abstract is if it implements an interface but does not provide
implementations for every method of the interface. This is a fairly unusual
circumstance however.
If a class has any abstract methods it must be declared abstract itself. |
Do not be distracted into thinking that an abstract class cannot have
non abstract methods. Any class that descends from an abstract
class must implement the abstract methods of the base class or declare
them as abstract itself. These rules tend to beg the question why would
you want to create abstract methods?
Abstract methods are mainly of benefit to class designers. They offer a class
designer a way to create a prototype for methods that ought to be implemented,
but the actual implementation is left to people who use the classes later on.
Here is an example of an abstract a class with an abstract method. Again
note that the class itself is declared abstract, otherwise a compile
time error would have occurred.
The following class is abstract and will compile correctly and print out the string
public abstract class abstr{ public static void main(String argv[]){ System.out.println("hello in the abstract"); } public abstract int amethod(); }
The final modifier can be applied to classes, methods and variables. It has similar meanings related to inheritance that make it fairly easy to remember. A final class may never be subclassed. Another way to think of this is that a final class cannot be a parent class. Any methods in a final class are automatically final. This can be useful if you do not want other programmers to "mess with your code". Another benefit is that of efficiency as the compiler has less work to do with a final method. This is covered well in Volume 1 of Core Java.
The final modifier indicates that a method cannot be overriden. Thus if you create a method in a sub class with exactly the same signature you will get a compile time error.
The following code illustrates the use of the final modifier with a class. This code will print out the string "amethod"
final class Base{ public void amethod(){ System.out.println("amethod"); } } public class Fin{ public static void main(String argv[]){ Base b = new Base(); b.amethod(); } }
A final variable cannot have it's value changed and must be set at creation time. This is similar to the idea of a constant in other languages.
The synchronized keyword is used to prevent more than one thread from accessing a block of code at a time. See section 7 on threads to understand more on how this works.
The transient keyword is one of the less frequently used modifiers. It indicates that a variable should not be written out when a class is serialized.
You probably will not get a question on the volatile keyword. The
worst you will get it is recognising that it actually is a Java keyword.
According to Barry Boone
"it tells the compiler a variable may change asynchronously due to
threads"
Accept that it is part of the language and then get on worrying about something
else
The visibility modifiers cannot be used in combination, thus a variable cannot be both private and public, public and protected or protected and private. You can of course have combinations of the visibility modifiers and the modifiers mentioned in my so forth list
Thus you can have a public static native method.
Modifier | Method | Variable | class |
public | yes | yes | yes |
private | yes | yes | yes (nested) |
protected | yes | yes | yes(nested) |
abstract | yes | no | yes |
final | yes | yes | yes |
transient | no | yes | no |
native | yes | no | no |
volatile | no | yes | no |
Create a file called Whitley.java. In this file define a class called Base with an abstract method called lamprey with an int return type. In this file create a class called Whitley that extends the base class. Give the Whitley class a method called lamprey and code that prints out the string "lamprey"..
Create a native method for the class called mynative. Now compile and run the code.
Create a public class called Malvern. Create a private inner class called Great that has a public void method called show. Make this method print out the string "Show". Give the class Malvern a public method called g that creates an instance of Great and calls its show method.. In the main method of Malvern create an instance of itself. Make the instance of itself call its go method. Compile and run the code.
abstract class Base{ abstract int lamprey(); } public class Whitley extends Base{ public static void main(String argv[]){ } public int lamprey(){ System.out.println("lamprey"); return 99; } native public void mynative(); }
public class Malvern{ public static void main(String argv[]){ Malvern m = new Malvern(); m.go(); } public void go(){ Great g = new Great(); g.show(); } private class Great{ public void show(){ System.out.println("Show"); } } }
What will happen when you attempt to compile and run this code?
abstract class Base{ abstract public void myfunc(); public void another(){ System.out.println("Another method"); } } public class Abs extends Base{ public static void main(String argv[]){ Abs a = new Abs(); a.amethod(); } public void myfunc(){ System.out.println("My func"); } public void amethod(){ myfunc(); } }
1) The code will compile and run, printing out the words "My
Func"
2) The compiler will complain that the Base class has non abstract methods
3) The code will compile but complain at run time that the Base class has non
abstract methods
4) The compiler will complain that the method myfunc in the base class has no
body, nobody at all to looove it
What will happen when you attempt to compile and run this code?
public class MyMain{ public static void main(String argv){ System.out.println("Hello cruel world"); } }
1) The compiler will complain that main is a reserved word and cannot be
used for a class
2) The code will compile and when run will print out "Hello cruel
world"
3) The code will compile but will complain at run time that no constructor is
defined
4) The code will compile but will complain at run time that main is not
correctly defined
Which of the following are Java modifiers?
1) public
2) private
3) friendly
4) transient
What will happen when you attempt to compile and run this code?
class Base{ abstract public void myfunc(); public void another(){ System.out.println("Another method"); } } public class Abs extends Base{ public static void main(String argv[]){ Abs a = new Abs(); a.amethod(); } public void myfunc(){ System.out.println("My func"); } public void amethod(){ myfunc(); } }
1) The code will compile and run, printing out the words "My
Func"
2) The compiler will complain that the Base class is not declared as
abstract.
3) The code will compile but complain at run time that the Base class has non
abstract methods
4) The compiler will complain that the method myfunc in the base class has no
body, nobody at all to looove it
Why might you define a method as native?
1) To get to access hardware that Java does not know about
2) To define a new data type such as an unsigned integer
3) To write optimised code for performance in a language such as C/C++
4) To overcome the limitation of the private scope of a method
What will happen when you attempt to compile and run this code?
class Base{ public final void amethod(){ System.out.println("amethod"); } } public class Fin extends Base{ public static void main(String argv[]){ Base b = new Base(); b.amethod(); } }
1) Compile time errror indicating that a class with any final methods must
be declared final itself
2) Compile time error indicating that you cannot inherit from a class with
final methods
3) Run time error indicating that Base is not defined as final
4) Success in compilation and output of "amethod" at run time.
What will happen when you attempt to compile and run this code?
public class Mod{ public static void main(String argv[]){ } public static native void amethod(); }
1) Error at compilation: native method cannot be static
2) Error at compilation native method must return value
3) Compilation but error at run time unless you have made code containing
native amethod available
4) Compilation and execution without error
What will happen when you attempt to compile and run this code?
private class Base{}
public class Vis{ transient int iVal; public static void main(String elephant[]){ } }
1) Compile time error: Base cannot be private
2) Compile time error indicating that an integer cannot be transient
3) Compile time error transient not a data type
4) Compile time error malformed main method
What happens when you attempt to compile and run these two files in the same directory?
//File P1.java
package MyPackage; class P1{ void afancymethod(){ System.out.println("What a fancy method"); } }
//File P2.java
public class P2 extends P1{ afancymethod(); }
1) Both compile and P2 outputs "What a fancy method" when run
2) Neither will compile
3) Both compile but P2 has an error at run time
4) P1 compiles cleanly but P2 has an error at compile time
Which of the following are legal declarations?
1) public protected amethod(int i)
2) public void amethod(int i)
3) public void amethod(void)
4) void public amethod(int i)
1) The code will compile and run, printing out the words "My Func"
An abstract class can have non abstract methods, but any class that extends
it must implement all of the abstract methods.
4) The code will compile but will complain at run time that main is not correctly
defined
The signature of main has a parameter of String rather than string array
1) public
2) private
4) transient
Although some texts use the word friendly when referring to visibility it is
not a Java reserved word. Note that the exam will almost certainly contain questions
that ask you to identify Java keywords from a list
2) The compiler will complain that the Base class is not declared as abstract.
The actual error message using my JDK 1.1 compiler was
Abs.java:1: class Base must be declared abstract. It does not define void myfunc () from class Base. class Base{ ^ 1 error
1) To get to access hardware that Java does not know about
3) To write optimised code for performance in a language such as C/C++
Although the creation of "Pure Java" code is highly desirable, particularly
to allow for platform independence, it should not be a religion, and there are
times when native code is required.
4) Success in compilation and output of "amethod" at run time.
This code calls the version of amethod in the Base class. If you were to attempt
to implement an overriden version of amethod in Fin you would get a compile
time error.
4) Compilation and execution without error
There is no call to the native method and so no error occurs at run time
1) Compile time error: Base cannot be private
A top level class such as base cannot be declared to be private.
4) P1 compiles cleanly but P2 has an error at compile time
Even though P2 is in the same directory as P1, because P1 was declared with
the package statement it is not visible from P2
2) public void amethod(int i)
If you thought that option 3 was legal with a parameter argument of void
you may have to empty some of the C/C++ out of your head.
Option 4) is not legal because method return type must come immediatly before
the method name.
This topic is covered in the Sun Tutorial at |