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.
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(){ }
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 will 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
public
public void toggleStatus()
protected
See "Using Packages to Organize Your Code," Chapter
11
protected void toggleStatus()
NOTE: 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.
void toggleStatus()
private
private void toggleStatus()
private protected
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
static
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 8.1), you create two instances of the Elevator class and perform some operations with them.
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.
NOTE: 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.
However, what if you want to define and modify a property for all elevators? Examine the example in Listing 8.2 and note the additions.
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 void toggleStatus();
CAUTION:
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 void toggleStatus()
native
native void toggleStatus();
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.
synchronized
synchronized void toggleStatus()
See "What Are Threads?" Chapter 13
Returning Information
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
Parameter List
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.
public class passingDemo { public void first(){ xObject o = new xObject (); o.x = 5; int x = 5; 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
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.
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.
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 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 to open a parameter list for a method and to establish a precedence for operations in an expression. |
) | Used both to close a parameter list for a method and to establish a precedence for operations in an expression. |
{ | Used to begin a block of statements or an initialization list. |
} | Used to close a block of statements or an initialization list. |
[ | Precedes an expression used as an array index. |
] | Follows an expression used as an array index. |
; | Used both to end an expression statement and to separate the parts of a for statement. |
, | Used as a list delimiter in many contexts. |
. | Used both as a decimal point and to separate such things as package name from class name from method or variable name. |