- Special Edition Using Java, 2nd Edition -

Chapter 10

Methods


by Joe Weber and Mike Afergan

Methods are truly the heart and soul of Java programs. Methods serve the same purpose in Java that functions do for C, C++, Pascal.... All execution, which takes place in any applet or application, takes place within a method, and only by combining multiple dynamic methods are large-scale quality Java applications written.

Parts of a Methods

Like C and C++ functions, Java methods are the essence of the class and are responsible for managing all tasks that will be performed. A method has two parts: a declaration and a body. While the actual implementation of the method is contained within the method’s body, a great deal of important information is defined in the method declaration.

The simplest method (and least useful) would look like this:

void SimpleMethod(){
}

Declaration

The declaration for a method is similar to the first line in the previous section. At the very least, it specifies what the method will return, and the name the method will be known by. Ordinarily, as you soon see, more options than these two are used. In general, method declarations have the form:

access_specifier modifier return_value nameofmethod (parameters)
throws ExceptionList

where everything in italics is optional.

Access Specifiers

The first option for a method is the access specifier. Access specifiers are used to restrict access to the method. Regardless of what the access specifier is, though, the method is accessible from any other method in the same class. However, while all methods in a class are accessible by all other methods in the same class, there are certain necessary tasks that you may not want other objects to be able to perform. You will learn more about classes in Chapter 12, “Classes.” But, for now, let's just look at how the access modifiers can change a method.

public

The public modifier is the most relaxed modifier possible for a method. By specifying a method as public it becomes accessible to all classes regardless of their lineage or their package. In other words, a public method is not restricted in any way.

public void toggleStatus()

protected

The second possible access modifier is protected. Protected methods can be accessed by any class within the current package, but are unaccessible to any class outside the package. For instance, the class java.awt.Component has a protected method paramString(), which is used in classes such as java.awt.Button, but which is unaccessible to any class that you might create.

[lbr][en]See “Using Packages,” p. xx [ch12]

protected void toggleStatus()

If you are having a compile-time error caused by an attempt to access a method not visible to the current scope, you may have trouble diagnosing the source of your problems. This is because the error message does not tell you that you are attempting to access a protected method. Instead it resembles the following:
 
No method matching paramString() found in class java.awt.Button.
 
(java.awt.Button.paramString() is a protected method in java.awt.Button.)
 
This is because the restricted methods are effectively hidden from the non-privileged classes. Therefore, when compiling a class that does not meet the security restrictions, such methods are hidden from the compiler.
 
Also note that you encounter a similar error message when trying to access a private or friendly method outside of its range of access as well as when you attempt to access a field from an unprivileged class.
 

friendly

The next access modifier that can be applied to a class is that of friendly. Friendly methods are accessible only to the current class and any classes that extend from it. By default, if you fail to specify an access modifier, the method is considered friendly.

void toggleStatus()

private

private is the highest degree of protection that can be applied to a method. A private method is only accessible by those methods in the same class. Even classes that extend from the current class do not have access to a private class.

private void toggleStatus()

private protected

There is a special version of the private method called private protected. Those methods declared to be private protected are accessible to both the class and any subclasses, but not the rest of the package nor any classes outside of the current package. This access is limited strictly to methods within the subclass. This means that while subclasses of the given class can invoke private protected methods of a given class, instances of the given class or its subclasses cannot.

For example:

class NetworkSender {
private protected void sendInfo(String mes) {
out.println(mes);
}
}
class NewNetworkSender extends NetworkSender {
void informOthers(String mes) {
NetworkSender me;
me = new NetworkSender();
super.sendInfo(mes); // this is legal
me.sendInfo(mes); // this is not
}
}

The first statement invokes sendInfo() as a method belonging to the superclass of NewNetworkSender. This is legal because private protected methods are accessible to subclasses. However, the second statement is illegal because it attempts to invoke sendInfo() on an instance of the NetworkSender class. Even though NewNetworkSender is a subclass of NetworkSender, it is referencing sendInfo() not as a method belonging to its superclass, but rather as a method belonging to an instance of NetworkSender.

Modifiers

Method modifiers enable you to set properties for the method, such as where it will be visible and how subclasses of the current class will interact with it.

static

Static, or class, variables, and methods are closely related.

static void toggleStatus()

It is important to differentiate between the properties of a specific instance of a class and the class itself. In the following code (see listing 10.1), you create two instances of the Elevator class and perform some operations with them.

Listing 10.1 Hotel.java Hotel example with Instance methods.

class Elevator {
boolean running = true;
void shutDown() {
running = false;
}
}
class FrontDesk {
private final int EVENING = 8;
Elevator NorthElevator, SouthElevator;
FrontDesk() { // the class constructor
NorthElevator = new Elevator();
SouthElevator = new Elevator();
}
void maintenance(int time) {
if (time == EVENING)
NorthElevator.shutDown();
}
void displayStatus() {
// code is very inefficient, but serves a purpose
System.out.print(“North Elevator is “);
if (!(NorthElevator.running ))
System.out.print(“not “);
System.out.println(“running.”);
System.out.print(“South Elevator is “);
if (!(SouthElevator.running ))
System.out.print(“ not “);
System.out.println(“running.”);
}
}
public class Hotel {
public static void main(String args[]) {
FrontDesk lobby;
lobby = new FrontDesk();
System.out.println(“It’s 7:00. Time to check the elevators.”);
lobby.maintenance(7);
lobby.displayStatus();
System.out.println();
System.out.println(“It’s 8:00. Time to check the elevators.”);
lobby.maintenance(8);
lobby.displayStatus();
}
}

Both NorthElevator and SouthElevator are instances of the Elevator class. This means that each is created with its own running variable and its own copy of the shutDown() method. While these are initially identical for both elevators, as you can see from the preceding example, the status of running in NorthElevator and SouthElevator does not remain equal once the maintenance() method is called.

Consequently, if compiled and run, the preceding code produces the following output:

C:\dev>\jdk\java\bin\java Hotel
It’s 7:00. Time to check the elevators.
North Elevator is running.
South Elevator is running.
It’s 8:00. Time to check the elevators.
North Elevator is not running.
South Elevator is running.

In the preceding example, you may notice a rather funny looking method named FrontDesk(). What is it? As you learn in the "Constructors" section later in Chapter 11, this is the constructor method for the FrontDesk class. Called whenever an instance of FrontDesk is created, it provides you with the ability to initialize fields and perform other such preparatory operations.
 

Variables and methods such as running and shutDown() are called instance variables and instance methods. This is because every time the Elevator class is instantiated, a new copy of each is created. In the preceding example, while the value of the running variable certainly can change because there are two copies of it, changing one does not change the other. Therefore, you can track the status of the NorthElevator and SouthElevator separately.

However, what if you want to define and modify a property for all elevators? Examine the example in listing 10.2 and note the additions.

Listing 10.2 Hotel2.java—Hotel example with static methods.

class Elevator {
boolean running = true;
static boolean powered = true;
void shutDown() {
running = false;
}
static void togglePower() {
powered = !powered;
}
}
class FrontDesk {
private final int EVENING = 8;
private final int CLOSING = 10;
private final int OPENING = 6;
Elevator NorthElevator, SouthElevator;
FrontDesk() {
NorthElevator = new Elevator();
SouthElevator = new Elevator();
}
void maintenance(int time) {
if (time == EVENING)
NorthElevator.shutDown();
else if ( (time == CLOSING) || (time == OPENING) )
Elevator.togglePower();
}
void displayStatus() {
// Code is very inefficient, but serves a purpose
System.out.print(“North Elevator is “);
if (!(NorthElevator.running ))
System.out.print(“not “);
System.out.println(“running.”);
System.out.print(“South Elevator is “);
if (!(SouthElevator.running ))
System.out.print(“ not “);
System.out.println(“running.”);
System.out.print(“The elevators are “);
if (!(Elevator.powered ))
System.out.print(“not “);
System.out.println(“powered.”);
}
}
public class Hotel2 {
public static void main(String args[]) {
FrontDesk lobby;
lobby = new FrontDesk();
System.out.println(“It’s 7:00. Time to check the elevators.”);
lobby.maintenance(7);
lobby.displayStatus();

System.out.println();
System.out.println(“It’s 8:00. Time to check the elevators.”);
lobby.maintenance(8);
lobby.displayStatus();
System.out.println();
System.out.println(“It’s 10:00. Time to check the elevators.”);
lobby.maintenance(10);
lobby.displayStatus();
}
}

In this case, the variable powered is now a static variable, and the method togglePower() is a static method. This means that each is now a property of all Elevator classes, not the specific instances. Invoking either the NorthElevator.togglePower(), SouthElevator.togglePower(), or Elevator.togglePower() method would change the status of the powered variable in both classes.

Consequently, the code would produce the following output:

C:\dev>\jdk\java\bin\java Hotel2
It’s 7:00. Time to check the elevators.
North Elevator is running.
South Elevator is running.
The elevators are powered.
It’s 8:00. Time to check the elevators.
North Elevator is not running.
South Elevator is running.
The elevators are powered.
It’s 10:00. Time to check the elevators.
North Elevator is not running.
South Elevator is running.
The elevators are not powered.

Placing the static modifier in front of a method declaration makes the method a static method. While non-static methods can also operate with static variables, static methods can only deal with static variables and static methods.

abstract

Abstract methods are simply methods that are declared, but are not implemented in the current class. The responsibility of defining the body of the method is left to subclasses of the current class.

abstract void toggleStatus();

Neither static methods nor class constructors can be declared to be abstract. Furthermore, you should not make abstract methods final, because doing so prevents you from overriding the method.
 

final

By placing the keyword final in front of the method declaration, you prevent any subclasses of the current class from overriding the given method. This ability enhances the degree of insulation of your classes, you can ensure that the functionality defined in this method will never be altered in any way.

final void toggleStatus()

native

Example: native void toggleStatus();

Native methods are methods that you want to use, but do not want to write in Java. Native methods are most commonly written in C++, and can provide several benefits such as faster execution time. Like abstract methods, they are declared simply by placing the modifier native in front of the method declaration and by substituting a semicolon for the method body.

However, it is also important to remember that the declaration informs the compiler as to the properties of the method. Therefore, it is imperative that you specify the same return type and parameter list as can be found in the native code.

See “Extending Java with Other Languages” Chapter 41 for more information.
 

synchronized

By placing the keyword synchronized in front of a method declaration, you can prevent data corruption that may result when two methods attempt to access the same piece of data at the same time. While this may not be a concern for simple programs, once you begin to use threads in your programs, this may become a serious problem.

synchronized void toggleStatus()

See “What are Threads?” Chapter 14 for more information.
 

Returning Information

While returning information is one of the most important things that a method can do, there is little to discuss by way of details about returning information. Java methods can return any data type ranging from simple ones, such as integers and characters, to more complex objects. (This means that you can return things such as strings as well.)

Keep in mind that unless you use the keyword void as your return type, you must return a variable of the type specified in your declaration.

For example, the following method is declared to return a variable of type boolean. The return is actually accomplished by employing the return (either true or false) statement in the third and fourth lines.

public synchronized boolean isEmpty(int x, int y) {
if (board[x][y] == EMPTY)
return true;
return false;
}

Method Name

The rules regarding method names are quite simple and are the same as any other Java identifier: begin with a Unicode letter (or an underscore or dollar sign) and continue with only Unicode characters.

Parameter List

Simply put, the parameter list is the list of information that will be passed to the method. It is in the form:

DataType VariableName, DataType VariableName,...

and can consist of as many parameters as you want.

Do note, however, that if you have no parameters, Java requires that you simply leave the parentheses empty. (This is unlike other languages that permit you to omit a parameter list, or C, which requires the keyword void.) Therefore, a method that took no parameters would have a declaration resembling:

public static final void cleanBoard()

Passing Parameters in Java

In C and C++, variables are always passed by value. In Pascal, they are always passed by reference. In Java, however, it depends on what data type you are using. This is probably the single most ambiguous part of the entire Java language. Here is the rule: if the type being passed is a primitive type (such as int, char, or float), then the result is passed by value. If, however, the type being passed is an Object (such as a Class you created), the object is passed by reference.

So what does this mean? As shown in listing 10.2, if you pass an int to a method and that method changes the int, in the old class the int still has the value it did before. However, when a class is passed and a variable is changed, the variable is changed in the old method, too. Take a look at listing 10.2.

Listing 10.2 PassingDemo.java—An example that demonstrates the difference between passing an object and a primitive type.

public class passingDemo {
public void first(){
xObject o = new xObject ();
o.x = 5;
int x = 5;
changeThem (x, o);
System.out.println();
System.out.println("Back in the original method");
System.out.println("The value of o.x is "+o.x);
System.out.println("But, The value of x is now "+x);
}
public void changeThem (int x, xObject o){
x =9;
o.x = 9;
System.out.println("In the changThem method");
System.out.println("The value of o.x is "+o.x);
System.out.println("The value of x is now "+x);
}
public static void main(String args[]){
passingDemo myDemo = new passingDemo();
myDemo.first();
}
}
class xObject {
public int x =5;
}

The resulting output from this code is:

In the changeThem method
The value of o.x is 9

The value of x is 9
Back in the original method
The value of o.x is 9
The value of x is 5

Blocks and Statements

Methods and static initializers in Java are defined by blocks of statements. A block of statements is a series of statements enclosed within curly-braces ({}). When a statement’s form calls for a statement or substatement as a part, a block can be inserted in the substatement’s place.

The simplest block {} is shown in the following example:

public void HiThere() {
}

The next example is only slightly more complex:


public void HiThere(){
int Test;
Test = 5;
}

Code blocks are not only integral for defining the start and end of a method, but they can also be used in a variety of locations throughout your code. One very important aspect of a block is that it is treated lexically as one instruction. This means that you can put together large blocks of code that will be treated as one instruction line.

There is nothing in the definition of Java that prevents the programmer from breaking code into blocks even though they are not specifically called for, but this is seldom done. The following code fragment demonstrates this legal but seldom done technique:

String Batter;
Short Inning, Out, Strikes;
Batsman Casey; // Object of class Batsman.
...
if ((Inning == 9) && (Out==2) && (Batter.equals(“Casey”))) {
Casey.manner(“ease”);
Casey.bearing(“pride”);
{ // Begins new block for no reason.
int OnlyExistsInThisBlock = 1;
Casey.face(“smile”);
Casey.hat(“lightly doff”);
} // Ends superfluous blocking.
}

Notice that this fragment contains two complete blocks. One is the substatement of the if statement, and the other is the unneeded block, which contains the unused integer OnlyExistsInThisBlock.

Labeled Statements

Any statement in Java can have a label. The actual label has the same properties as any other identifier; it cannot have the same name as a keyword or already declared local identifier. If it has the same name as a variable, method, or type name that is available to this block, then within that block, the new label takes precedence and that outside variable, method, or type is hidden. It has the scope of the current block. The label is followed by a colon.

Labels are only used by the break and continue Jump statements.

An example of labeled statements appears in the following code fragment:

writhing:
Pitcher.GrindsBall(“Hip”);
Casey.eye(“Defiance Gleams”);
Casey.lip(“Curling Sneer”);
pitch: while (strike++ < 2) {
if (strike < 2) continue pitch;
break writhing;
}

The statement, writhing, is simple labeling of an expression statement, in this case, a method call from a rather complicated object called Pitcher. The statement pitch is labeling an iteration statement (while). This label is used as a parameter for the continue statement.

Scope

Another use of blocks is to control what is known as the scope of an object. When you declare a variable, it is only available for your use within a given code block. For instance, say you had the following block:

{
int x= 5;
}
System.out.println (“X is =“+x); // This line is not valid.

The last line of this code would not be valid, because the computer creates the x variable, but when the computer reaches the closing brace, it gets rid of x.

Separators

Separators are single-character tokens, which (as their name implies) are found between other tokens. There are nine separators, which are loosely described as follows:

. Used both as a decimal point and to separate such things as package name from class name from method or variable name.

 


Previous PageTOCNext Page

| Previous Chapter | Next Chapter |

| Table of Contents | Book Home Page |

| Que Home Page | Digital Bookshelf | Disclaimer |


To order books from QUE, call us at 800-716-0044 or 317-361-5400.

For comments or technical support for our books and software, select Talk to Us.

© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.