Previous
Index

Next


Objective 2, Declaring classes and variables

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.

Comment on the objective

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

What is a class?

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.

Comparing C++/VB classes with Java

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.

The role of classes in Java

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 simplest of class

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
}

Creating a simple HelloWorld class

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.

Creating an instance of a class

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.

Creating Methods

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 local 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
}
       

Modifiers and encapsulation

Key Concept Logo

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

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
}
       

Public

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.

Protected

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

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
        }
}
    

Key Concept Logo

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"

    


Key Concept

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"

       

Native

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();
       

Abstract

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();
}

 
       

Final

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.

Synchronized

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.

Transient

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.

Volatile

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

Using modifiers in combination

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.



Where modifiers can be used

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



    
   

Questions

Question 1)

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




Question 2)

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




Question 3)

Which of the following are Java modifiers?

1) public
2) private
3) friendly
4) transient


Question 4)

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


Question 5)

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




Question 6)

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.




Question 7)

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





Question 8)

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




Question 9)

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


Question 10)

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)


Answers

Answer 1)

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.

Answer 2)

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


Answer 3)

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

Answer 4)

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
       

Answer 5)

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.

Answer 6)

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.

Answer 7)

4) Compilation and execution without error

There is no call to the native method and so no error occurs at run time

Answer 8)

1) Compile time error: Base cannot be private

A top level class such as base cannot be declared to be private.

Answer 9)

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


Answer 10)

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.


Other sources on this topic

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
Index

Next