What are Methods?

Types of Methods

Java methods are an integral part of the Java program, falling into a few categories like instance methods, class methods, helper methods, and constructors.

Many technical conversations about a Java program concern methods in some way. This focus is not overstated: all Java programs contain at least one method, the main method. All methods contain a heading and a block of code, and many receive and use parameters of some type.

Yet the methods available to the Java programmer falls into several descriptive categories: instance methods, class methods, helper methods, and constructors. All methods can also be organized according to whether or not they return a result from their operations.

Instance Method

When an object is instantiated, it is created based on its class definition. This object typically has instance fields, its own copied set of the standard fields of its class definition. Likewise, an instance method is associated with an object of a class rather than a class itself. For example:

System.out.println(“This is text.”);

Println is here an instance method associated with the out object that has been instantiated. The out object belongs to the System class; note that the more names tacked on to the right of the class name (System.out.println versus System.out) the more specific the reference becomes.

Class Methods

A method that belongs to its class rather than to an object of that class, as described above, is a class method. While an instance method has access to both instance fields and class fields, a class method has access only to the class fields. A class method is declared with a modifier, like so:

public static void methodName(){}

The static keyword sticks the method to the class rather than to objects of that class. When the class method is called, its name is tacked next to the class name rather than to an object of that name:

class.classMethod();

Class methods are useful for creating constants and class fields that need to be used throughout a program.

Helper Methods

Helper methods are exclusive to a class; only other methods in the same class can call this type of method. They are made exclusive with another use of declaring modifiers. Rather than the typical method heading of:

public void methodName(){}

Helper methods use the private keyword:

private void methodName(){}

Furthermore, a call to a helper method does not involve sticking the method name to a class name or object name as with instance methods and class methods. Rather than System.methodName();, a call to a helper method would simply be methodName();

Since the private method is in the same class and can only be used by methods in that class, there's no point in using the hierarchical referencing when calling these methods. Helper methods are typically used in complex classes that need careful organization to make sense to the programmer, or to perform tasks that are needed only in that class.

Constructor Methods

Constructor methods are unique among methods, sharing little similarities and many differences with typical methods. First of all, constructor methods exist only to instantiate a class, not to execute code. Second, constructor methods have no return type at all, not even void, and have only one modifier in their heading.

While constructor methods are not required, a blank one is automatically loaded if none is present and multiple constructor methods with the same name can be written in a process known as overloading.

Special method for creating new instance of a class. Must have the same name as the class it constructs. Below (line 4) is the constructor for Cat.


Accessor Methods

Methods that return variables. The accessor method name should start with "get". Below (line 8) is the accessor named getCatsColor.


Mutator Methods

Methods that alter variables. The mutator method name should start with "set". Below (line 12) is the accessor named setCatsColor.

1 class Cat {

2     private static String animalType = "feline";

3     private String catColor;

4     Cat(String colorIn)

5     {

6         setCatsColor(colorIn);    

7     }

8     public String getCatsColor()

9     {

10        return this.catColor;  

11    }

12    public String setCatsColor()

13    {

14        this.catColor;  

15    }

16    

17    public static void main (String[] argsIn) {

18        Cat patches = new Cat("calico");

19    }

20 }     

Signature or Method Signature

What variable types and in what order they are passed to a method. The return type is not a part of the signature. In the folowing method "String, double" is the signature:

public int returnAnInt(String stringIn, double doubleIn) {

    int intToReturn = 1;

    if (stringIn.equals(String.valueOf(doubleIn))

        {

            intToReturn = 2;

        }

        

    return intToReturn;

}

Overloaded Methods

Two or more methods with same name, different signature, return types can vary - but do not have to.

public int returnOneNoMatterWhat(String stringIn, double doubleIn) {

    int intToReturn = 1;

    return intToReturn;

}         

public int returnOneNoMatterWhat(int intIn) { int intToReturn = 1; return intToReturn; }

Summary

Methods, like many parts of Java, are a complex topic requiring a bit of time and study to understand completely.

Calling a Method

A method is a set of code which is referred to by name and can be called (invoked) at any point in a program simply by utilizing the method's name.  Think of a method as a subprogram that acts on data and often returns a value.

Each method has its own name.  When that name is encountered in a program, the execution of the program branches to the body of that method.  When the method is finished, execution returns to the area of the program code from which it was called, and the program continues on to the next line of code.

Good programmers write in a modular fashion which allows for several programmers to work independently on separate concepts which can be assembled at a later date to create the entire project.  The use of methods will be our first step in the direction of modular programming.

Methods are time savers, in that they allow for the repetition of sections of code without retyping the code.  In addition, methods can be saved and utilized again and again in newly developed programs.

You are using methods when you use
 
System.out.print( ) and System.out.println( ).

There are two basic types of methods: 

Built-in:  Build-in methods are part of the compiler package, such as System.out.println( ) and  System.exit(0).
 
User-defined: User-defined methods are created by you, the programmer. These methods take-on names that you assign to them and perform tasks that you create.

How to invoke (call) a method (method invocation):

When a method is invoked (called), a request is made to perform some action, such as setting a value, printing statements, returning an answer, etc.  The code to invoke the method contains the name of the method to be executed and any needed data that the receiving method requires.  The required data for a method are specified in the method's parameter list.

Consider this method that we have already been using from Breezy;

      int number = Console.readInt("Enter a number");  //returns a value

The method name is "readInt" which is defined in the class "Console".  Since the method is defined in the class Console, the word Console becomes the calling object.  This particular method returns an integer value which is assigned to an integer variable named number.

You invoke (call) a method by writing down the calling object followed by a dot, then the name of the method, and finally a set of parentheses that may (or may not) have information for the method.

Defining Methods

Here is an example of a typical method declaration:

public double calculateAnswer(double wingSpan, 
                  int numberOfEngines,
                  double length,
                  double grossTons) {
    //do the calculation here
}

The only required elements of a method declaration are the method's return type, name, a pair of parentheses, (), and a body between braces, {}.

More generally, method declarations have six components, in order:

  1. Modifiers—such as public, private, and others you will learn about later.
  2. The return type—the data type of the value returned by the method, or void if the method does not return a value.
  3. The method name—the rules for field names apply to method names as well, but the convention is a little different.
  4. The parameter list in parenthesis—a comma-delimited list of input parameters, preceded by their data types, enclosed by parentheses, (). If there are no parameters, you must use empty parentheses.
  5. An exception list—to be discussed later.
  6. The method body, enclosed between braces—the method's code, including the declaration of local variables, goes here.

Modifiers, return types, and parameters will be discussed later in this lesson. Exceptions are discussed in a later lesson.


Definition: 

Two of the components of a method declaration comprise the method signature—the method's name and the parameter types.


The signature of the method declared above is:

calculateAnswer(double, int, double, double)

Naming a Method

Although a method name can be any legal identifier, code conventions restrict method names. By convention, method names should be a verb in lowercase or a multi-word name that begins with a verb in lowercase, followed by adjectives, nouns, etc. In multi-word names, the first letter of each of the second and following words should be capitalized. Here are some examples:

run
runFast
getBackground
getFinalData
compareTo
setX
isEmpty

Typically, a method has a unique name within its class. However, a method might have the same name as other methods due to method overloading.

Method Parameters - Passing Information to a Method or a Constructor

The declaration for a method or a constructor declares the number and the type of the arguments for that method or constructor. For example, the following is a method that computes the monthly payments for a home loan, based on the amount of the loan, the interest rate, the length of the loan (the number of periods), and the future value of the loan:

public double computePayment(
                  double loanAmt,
                  double rate,
                  double futureValue,
                  int numPeriods) {
    double interest = rate / 100.0;
    double partial1 = 
        Math.pow((1 + interest), 
                  -numPeriods);
    double denominator = (1 - partial1) / interest;
    double answer = (-loanAmt / denominator)
                    - ((futureValue * partial1) / denominator);
    return answer;
}

This method has four parameters: the loan amount, the interest rate, the future value and the number of periods. The first three are double-precision floating point numbers, and the fourth is an integer. The parameters are used in the method body and at runtime will take on the values of the arguments that are passed in.


Note: 

Parameters refers to the list of variables in a method declaration. Arguments are the actual values that are passed in when the method is invoked. When you invoke a method, the arguments used must match the declaration's parameters in type and order.


Parameter Types

You can use any data type for a parameter of a method or a constructor. This includes primitive data types, such as doubles, floats, and integers, as you saw in the computePayment method, and reference data types, such as objects and arrays.

Here's an example of a method that accepts an array as an argument. In this example, the method creates a new Polygon object and initializes it from an array of Point objects (assume that Point is a class that represents an x, y coordinate):

public Polygon polygonFrom(Point[] corners) {
    // method body goes here
}

Note: 

The Java programming language doesn't let you pass methods into methods. But you can pass an object into a method and then invoke the object's methods.


Arbitrary Number of Arguments

You can use a construct called varargs to pass an arbitrary number of values to a method. You use varargs when you don't know how many of a particular type of argument will be passed to the method. It's a shortcut to creating an array manually (the previous method could have used varargs rather than an array).

To use varargs, you follow the type of the last parameter by an ellipsis (three dots, ...), then a space, and the parameter name. The method can then be called with any number of that parameter, including none.

public Polygon polygonFrom(Point... corners) {
    int numberOfSides = corners.length;
    double squareOfSide1, lengthOfSide1;
    squareOfSide1 = (corners[1].x - corners[0].x)*(corners[1].x - corners[0].x) 
                     + (corners[1].y - corners[0].y)*(corners[1].y - corners[0].y) ;
    lengthOfSide1 = Math.sqrt(squareOfSide1);

    // more method body code follows 
    // that creates and returns a 
    // polygon connecting the Points
}

You can see that, inside the method, corners is treated like an array. The method can be called either with an array or with a sequence of arguments. The code in the method body will treat the parameter as an array in either case.

You will most commonly see varargs with the printing methods; for example, this printf method:

public PrintStream printf(String format,
                          Object... args)

allows you to print an arbitrary number of objects. It can be called like this:

System.out.printf("%s: %d, %s%n", 
                  name, idnum, address);

or like this

System.out.printf("%s: %d, %s, %s, %s%n",
                  name, idnum, address,
                  phone, email);

or with yet a different number of arguments.

Parameter Names

When you declare a parameter to a method or a constructor, you provide a name for that parameter. This name is used within the method body to refer to the passed-in argument.

The name of a parameter must be unique in its scope. It cannot be the same as the name of another parameter for the same method or constructor, and it cannot be the name of a local variable within the method or constructor.

A parameter can have the same name as one of the class's fields. If this is the case, the parameter is said to shadow the field. Shadowing fields can make your code difficult to read and is conventionally used only within constructors and methods that set a particular field. For example, consider the following Circle class and its setOrigin method:

public class Circle {
    private int x, y, radius;
    public void setOrigin(int x, int y) {
        ...
    }
}

The Circle class has three fields: x, y, and radius. The setOrigin method has two parameters, each of which has the same name as one of the fields. Each method parameter shadows the field that shares its name. So using the simple names x or y within the body of the method refers to the parameter, not to the field. To access the field, you must use a qualified name. This will be discussed later in this lesson in the section titled "Using the this Keyword."

Passing Primitive Data Type Arguments

Primitive arguments, such as an int or a double, are passed into methods by value. This means that any changes to the values of the parameters exist only within the scope of the method. When the method returns, the parameters are gone and any changes to them are lost. Here is an example:

public class PassPrimitiveByValue {

    public static void main(String[] args) {
           
        int x = 3;
           
        // invoke passMethod() with 
        // x as argument
        passMethod(x);
           
        // print x to see if its 
        // value has changed
        System.out.println("After invoking passMethod, x = " + x);
           
    }
        
    // change parameter in passMethod()
    public static void passMethod(int p) {
        p = 10;
    }
}

When you run this program, the output is:

After invoking passMethod, x = 3

Passing Reference Data Type Arguments

Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object's fields can be changed in the method, if they have the proper access level.

For example, consider a method in an arbitrary class that moves Circle objects:

public void moveCircle(Circle circle,
                       int deltaX,
                       int deltaY) {
    // code to move origin of 
    // circle to x+deltaX, y+deltaY
    circle.setX(circle.getX() + deltaX);
    circle.setY(circle.getY() + deltaY);
        
    // code to assign a new 
    // reference to circle
    circle = new Circle(0, 0);
}

Let the method be invoked with these arguments:

moveCircle(myCircle, 23, 56)

Inside the method, circle initially refers to myCircle. The method changes the x and y coordinates of the object that circle references (i.e., myCircle) by 23 and 56, respectively. These changes will persist when the method returns. Then circle is assigned a reference to a new Circle object with x = y = 0. This reassignment has no permanence, however, because the reference was passed in by value and cannot change. Within the method, the object pointed to by circle has changed, but, when the method returns, myCircle still references the same Circle object as before the method was called.

Method Scope - Declarations and Access Control

  • names are used to identify entities declared in a program ie classes, methods, variables, parameters, etc
  • each name or identifier occupies a particular namespace
  • every declaration has a scope; the areas of a program from which it can be accessed by its simple name
Declaration Scope (accessible from)
package all compilation units within the package
import all the classes and interfaces within the compilation unit (source code file)
class or interface all other declarations within the same file
label the statements immeadiately enclosed by the labeled statement ie if a loop is labelled, everything declared within the loop-construct has access to the label
member the body of the class and anything declared within the class
parameter the body of the method or constructor
local variable the code block in which the declaration occurs
local class the enclosing block including the local class body
local variable in a for-loop initializer the body of the for-loop
parameter in a catch clause the body of the catch clause

Order of searching for an identifier

  • when a name (identifier) is used; the meaning, or scope, of it's name is searched for based on where it appears in the code starting with:
  1. if used in a code block, for-loop, or in a catch clause, search is for a local variable within the enclosing construct
  2. if in a method or constructor, searches for a matching parameter
  3. search continues for a class or interface member, including inherited members
  4. if its a nested type, searches enclosing block or class. If its a static type, only static members of enclosing blocks or classes are searched.
  5. explicitly named imported types
  6. other types declared in the same package
  7. implicitly named imported types
  8. packages on the host system

Shadowing

  • Because of the way identifiers are looked up; shadowing declarations can occur
  • For example, a field declaration can be shadowed by a local variable declaration

class TestShadowing {

  static int x = 1;           // field variable

  

  public static void main(String[] args) {

      int x = 0;              // local variable

      System.out.println("x = " + x);

      System.out.println("TestShadowing.x = " + TestShadowing.x)

  }

}



Output:

    x = 0

    TestShadowing.x = 1

  • because the identifier x is used within a code block main() a search is made for a declaration of x within the body of main(). As one is found, int x = 0, the simple identifier name x is assumed to be within scope as a local variable
  • to access the field variable x, you must use its fully-qualified name TestShadowing.x
Note
  • it was not necessary to instantiate an instance of the TestShadowing object to access the static field variable. If x had been an instance variable it would have been necessary to create a new instance of TestShadowing and use it's reference to access x

Hiding

  • Shadowing is not the same as hiding
  • hiding applies to members that would normally be inherited but are not because of a declaration of the same identifier in a subclass

class SuperA {

    int x = 10;

}



class SubA extends SuperA {

    int x = 20;           // hides x in superclass

}

  • a method can hide a method in the superclass by overriding it
static Methods cannot be overridden
  • a method cannot override a static method in the superclass; however, it can hide it by using the same declaration

class SuperA {

    static void method2() {

    }

}



class SubA extends SuperA() {

    void method2() {

        // declaration causes a compile-error

    }

    

    static void method2() {

        // compiles ok

    }

}

  • static methods are hidden vs overridden as the JLS states they "cannot be overridden" so the compiler never compares subclass method declarations to static superclass method declarations.
  • a static method in a subclass cannot hide an instance method in the superclass

class SuperA {

    void method1() {

    }

}



class SubA extends SuperA() {



    static void method1() {

        // compile-error

    }

}

  • a hidden method can be accessed by using super(), casting to the superclass or using the methods fully qualified name

    ((SuperA)y).method2();  // cast to access hidden method    

  • instance variables can hide static and non-static variables in the superclass

Obscuring

  • there may be times when a simple name could be interpreted as a variable, a type or a package
  • based on the rules, a variable will be chosen before a type, and a type before a package
  • in such situations a declaration is said to be obscured
  • following naming conventions helps to avoid obscuring