Classes

 


 

Creating Classes

The key elements of a class include:

Vector is an expandable array of objects, which the Stack class uses to store elements. Elements are added to, and removed from, the top of the stack only, using the LIFO algorithm.

 


 

HelloWorld Class

The System.out.println method in the HelloWorldApp application prints a variable from the System class.

class HelloWorldApp 
{
    public static void main(String[] args) 
    {
        System.out.println("Hello World!"); 
    }
}

The application never instantiates the System class. Instead, out is referred to directly from the class name, System, which makes out a class variable. To use class variables, one joins the class name and the name of the class method or variable together with a period (".").

While System's out variable is a class variable, it refers to an instance of the PrintStream class that implements the standard output stream. When the System class is loaded into the application, it instantiates PrintStream and assigns the new PrintStream object to the out class variable. Now that there an instance of a class has been created, one can call instance methods:

System.out.println("Hello World!");
One refers to instance methods and variables by joining an object reference (out) and the name of the instance method or variable (println) together with a period ("."). The compiler allows you to cascade references to class and instance methods and variables together, resulting in constructs like the one that appears in the sample program:

 

 

Class Declaration

The previous diagram shows that two primary components make up the implementation of a class: the class declaration and the class body. The class declaration declares the name of the class along with other attributes. The class declaration for the Stack class is fairly simple and indicates that the class is public and that its name is Stack. Often, a minimal class declaration such as this one is all you'll need.

However, the class declaration can say more about the class, such as the name of the superclass and if it can be subclassed.

 

The Class Body The class body follows the class declaration and is embedded within curly braces { and }. The class body contains all of the code that provides for the life cycle of the objects created from it: constructors for initializing new objects, declarations for the variables that provide the state of the class and its objects, methods to implement the behavior of the class and its objects, and in rare cases, a finalize method to provide for cleaning up an object after it has done its job.

Variables and methods collectively are called members.

Constructors are not methods. Nor are they members.

The Stack class defines one member variable in its body to contain its elements--the items Vector. It also defines one constructor--a no-argument constructor--and three methods: push, pop, and isEmpty.

 

 

Providing Constructors for Your Classes

A class may contain one or more constructors that provide for the initialization of an object created from the class. This section shows you how to write a constructor.

 

 

Declaring Member Variables

A class's state is represented by its member variables. You declare a class's member variables in the body of the class. Typically, you declare a class's variables before you declare its methods, although this is not required.

classDeclaration 
{
    member variable declarations
    method declarations
}

To declare variables that are members of a class, the declarations must be within the class body, but not within the body of a method. Variables declared within the body of a method are local to that method.

 

 

Implementing Methods

Objects have behavior that is implemented by its methods. Other objects can ask an object to do something by invoking its methods. This section tells you everything you need to know about writing methods for your Java classes.

In Java, you define a class's methods in the body of the class for which the method implements some behavior. Typically, you declare a class's methods after its variables in the class body although this is not required.

Set access rights to members using access specifiers.

This figure shows the code for Stack's push method. This method pushes an object, the one passed in as an argument, onto the top of the stack, and returns it.

Like a class, a method has two major parts:

  1. method declaration
  2. method body.

 

 

The Method Declaration

At minimum, a method declaration has a name and a return type indicating the data type of the value returned by the method:


returnType methodName() 
{
    . . .
}

This method declaration is very basic. Methods have many other attributes such as arguments, access control, and so on. This section will cover these topics as well as expand upon the features illustrated in the method declaration above.

A method's declaration provides a lot of information about the method to the compiler, to the runtime system, and to other classes and objects. Included is not only the name of the method, but also such information as the return type of the method, the number and type of the arguments required by the method, and which other classes and objects can call the method.

The only required elements of a method declaration are the method's name, its return type, and a pair of parentheses ( ). This figure shows the elements of a method declaration.

Each element of a method declaration is further defined below:

accessLevel

As with member variables, you control which other classes have access to a method using one of four access levels: public, protected, package, and private. Controlling Access to Members of a Class covers access levels in detail.

static

As with member variables, static declares this method as a class method rather than an instance method. Understanding Instance and Class Members talks about declaring instance and class methods.

abstract

An abstract method has no implementation and must be a member of an abstract class.

how they affect subclasses,

native

If you have a significant library of functions written in another language such as C, you may wish to preserve that investment and use those functions from Java. Methods implemented in a language other than Java are called native methods and are declared as such using the native keyword.

synchronized

Concurrently running threads often invoke methods that operate on the same data. These methods may be declared synchronized to ensure that the threads access information in a thread-safe manner.

returnType

Java requires that a method declare the data type of the value that it returns. If your method does not return a value, use the keyword void for the return type. Returning a Value from a Method talks about the issues related to returning values from a method.

methodName

A method name can be any legal Java identifier. You need to consider several issues in regards to Java method names. These are covered in Method Names.

( paramlist )

You pass information into a method through its arguments. See the next section, Passing Information into a Method.

[throws exceptions]

If your method throws any checked exceptions, your method declaration must indicate the type of those exceptions.

 

 

Returning a Value from a Method

Any method that is not declared void must contain a return statement. The Stack class declares the isEmpty method, which returns a boolean:

public boolean isEmpty() 
{
    if (items.size() == 0)
        return true;
    else
        return false;
}

The data type of the return value must match the method's return type; you can't return an Object type from a method declared to return an integer. The isEmpty method returns either the boolean value true or false, depending on the outcome of a test. A compiler error results if you try to write a method in which the return value doesn't match the return type.

The isEmpty method returns a primitive type. Methods also can return a reference type. For example, Stack declares the pop method that returns the Object reference type:

public synchronized Object pop() 
{
    int len = items.size();
    Object obj = null;
    if (len == 0)
        throw new EmptyStackException();
    obj = items.elementAt(len - 1);
    items.removeElementAt(len - 1);
    return obj;
}
When a method returns an object such as pop does, the class of the returned object must be either a subclass of or the exact class of the return type. Suppose you have a class hierarchy where ImaginaryNumber is a subclass of java.lang.Number, which is, in turn, a subclass of Object. as illustrated here:

Now suppose you have a method declared to return a Number:
public Number returnANumber() 
{
    . . .
}
The returnANumber method can return an ImaginaryNumber but not an Object. ImaginaryNumber "is a" Number because it's a subclass of Number. However, an Object is not necessarily a Number--it could be a String or some other type. You also can use interface names as return types. In this case, the object returned must implement the specified interface.

 

 

A Method's Name

Java supports method name overloading so that multiple methods can share the same name. For example, suppose you are writing a class that can render various types of data (strings, integers, and so on) to its drawing area. You need to write a method that knows how to render each data type. In other languages, you have to think of a new name for each method, for example, drawString, drawInteger, drawFloat, and so on. In Java, you can use the same name for all of the drawing methods but pass a different type of parameter to each method. So, in your data rendering class, you can declare three methods named draw, each of which takes a different type of parameter:
class DataRenderer 
{
    void draw(String s) 
    {
        . . .
    }
    void draw(int i) 
    {
        . . .
    }
    void draw(float f) 
    {
        . . .
    }
}

Overloaded methods are differentiated by the number and type of the arguments passed into the method. In the code sample, draw(String s) and draw(int i) are distinct and unique methods because they require different argument types. You cannot declare more than one method with the same name and the same number and type of arguments because the compiler cannot differentiate them. So, draw(String s) and draw(String t) are identical and result in a compiler error.

A class may override a method in its superclass. The overriding method must have the same name, return type, and parameter list as the method it overrides.

 

 

Passing Information into a Method

Perhaps the most commonly used optional component of a method declaration are method parameters. Similar to functions in other programming languages, Java methods accept input from the caller through its parameters. Parameters provide information to the method from outside the scope of the method.

 

 

The Method Body

The method body is where all of the action of a method takes place; the method body contains all of the legal Java instructions that implement the method.

 

 

Managing Inheritance

The extends clause declares that your class is a subclass of another. You can specify only one superclass for your class. You can omit the extends clause from your class declaration and your class wll still have a superclass.

The top-most class, the class from which all other classes are derived, is java.lang.Object. A subclass inherits state and behavior from all of its ancestors.

 

 

Implementing Nested Classes

A nested class is a member of another class.

class EnclosingClass
{
    . . .
    class ANestedClass 
    {
        . . .
    }
}

They are used to reflect and enforce the relationship between two classes.

A nested class has unlimited access to its enclosing class's members, even if they are declared private.

Like other members, a nested class can be declared static (or not). A static nested class is called just that: a static nested class. A nonstatic nested class is called an inner class. These are illustrated in the following code:

class EnclosingClass
{
    . . .
    static class AStaticNestedClass 
    {
        . . .
    }
    class InnerClass 
    {
        . . .
    }
}

As with static methods and variables (normally called class methods and variables), a static nested class is associated with its enclosing class. And like class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class-it can use them only through an object reference.

As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's instance variables and methods. Also, because an inner class is associated with an instance, it cannot define any static members itself.

To help differentiate the terms nested class and inner class further, we suggest you think about them in the following way. The term "nested class" reflects the syntactic relationship between two classes; that is, syntactically, the code for one class appears within the code of another. In contrast, the term "inner class" reflects the relationship between instances of the two classes. Consider the following classes:

class EnclosingClass 
{
    . . .
    class InnerClass 
    {
        . . .
    }
}

The interesting feature about the relationship between these two classes is not that InnerClass is syntactically defined within EnclosingClass. Rather, it's that an instance of InnerClass can exist only within an instance of EnclosingClass and that it has direct access to instance variables and methods of its enclosing instance. The following diagram illustrates this idea.

You may encounter nested classes of both kinds in the Java API and be required to use them. However, most nested classes that you write will be inner classes.

An inner class is a nested class whose instance exists within an instance of its enclosing class and has direct access to the instance members of its enclosing instance.

Like other classes, nested classes can be declared abstract The meaning of these two modifiers for nested classes is the same as for other classes. Also, the access specifiers, private, public, protected, and package, may be used to restrict access to nested classes just as they do to other class members.

Any nested class, not just anonymous ones, can be declared in any block of code. A nested class declared within a method or other smaller block

 

Home