Previous |
Next |
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,
native
transient
synchronized
volatile
One rather dry definition of a class describes it as "an aggregation of methods and data". It is possibly more instructive to view the concept in the light of the thinking on programming that came before classes. The main programming concept before Classes and Object Orientation was that of structured programming. The idea of structured programming is that the programmer breaks down a complex problem into small chunks of code known variously as functions or subroutines. This fits into the idea that a good way to deal with a large complex problem is by breaking it up into a sequence of smaller more manageable problems.
Although structured programming has great benefits in terms of managing complexity it does not lead itself easily to re-use code. Programmers found themselves constantly "re-inventing" the wheel. In an attempt to take ideas from the world of physical object thinkers on programming came up with the object of Object Orientation (sometimes called OO).
Take the example of a computer manufacturer coming up with a new model of PC. If computer manufacturers used a similar process to much of the world of programming, this would involve starting setting teams to design a new CPU chip, a new video chip and maybe another team to design, layout and create a motherboard. In reality this doesn't happen. Because of the standardisation of interfaces in computer components, manufacturers contact the component suppliers and negotiate the specifications of the machine they are going to create. Note the significance of the standardisation of the interfaces of the components.
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.
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. Utility code is often kept in static methods, thus the Math class class has an entire set of utility methods such as random, sin, and round, and the primitive wrapper classes Integer, Double etc have static methods for manipulating the primitives they wrap, such as returning the matching int value from the string "2".
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. Iin the following example of a non static int three instances of the int 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. Also a non static (normal) method cannot be overriden to be 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"
Static methods cannot be overriden in a child class but they can be hidden. |
In one of my mock exams I have a question that asks if static methods can be overriden. The answer given is that static methods cannot be overriden, but that lead to a considerable number of emails from people giving examples where it appears that static methods have been overriden. The process of overriding involves more than simply replacing a method in a child class, it involves the runtime resolution of what method to call according to its reference type.
Here is an example of some code that appears to show overriding of static methods
class Base{ public static void stamethod(){ System.out.println("Base"); } } public class ItsOver extends Base{ public static void main(String argv[]){ ItsOver so = new ItsOver(); so.stamethod(); } public static void stamethod(){ System.out.println("amethod in StaOver"); } } This code will compile and output "amethod in StaOver"
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 or 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 void 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 overridden. 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
native
transient
synchronized
volatile
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 |
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 error 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 overridden 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
immediately before the method name.
The Java Language Specification
http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#10428
This topic is covered in the Sun tutorial at
Class modifiers
http://java.sun.com/docs/books/tutorial/reflect/class/getModifiers.html
Controlling access to members of a class
http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html
The Java Language Specification
http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#227928
Jyothi Krishnan on this topic at
http://www.geocities.com/SiliconValley/Network/3693/obj_sec1.html#obj2
Bruce Eckel Thinking in Java
http://codeguru.earthweb.com/java/tij/tij0056.shtml
The Sun tutorial comments on Static methods and
overriding
http://java.sun.com/docs/books/tutorial/java/javaOO/override.html
Connecticut State University
http://chortle.ccsu.ctstateu.edu/cs151/Notes/chap33/ch33_1.html
Inner classes: Chapter 7 from Mughal and Rasumussen
http://developer.java.sun.com/developer/Books/certification/certbook.pdf
Previous |
Next |