SCJP Study Guide:
Declarations, Initialization and Scoping


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend


Previous Next vertical dots separating previous/next from contents/index/pdf Contents
XyzWs SCJP Study Guide: Methods

Java Methods

The word method is commonly used in Object-Oriented Programming and is used in Java. Every programmer has this idea, but sometimes uses other terms such as function, procedure, subroutine, ... Many programmers use these other terms, especially function, but these notes will use method.

Similar to a class implementation, a method implementation consists of two parts: the method declaration and the method body.

methodDeclaration {
    methodBody
}

A method declaration names the method's access level, return type, name, arguments, and the method body, as shown in the following method's syntax. The method body is where all the action takes place. It contains the instructions that implement the method.

The Method Declaration

A method's declaration provides a lot of information about the method to the compiler, the runtime system and to other classes and objects. Besides the name of the method, the method declaration carries information such as the return type of the method, the number and type of the arguments required by the method, and what other classes and objects can call the method.

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. 

Besides the two required elements of a method declaration, a method declaration may contain other elements as well. These elements declare the arguments accepted by the method, whether the method is a class method, and so on.

The general syntax for a method declaration looks like this:

[modifiers] return_type method_name (parameter_list) [throws_clause] {

   [statement_list]
}

Everything within square brackets [] is optional.  You can see that the minimal method declaration includes:

  • Return Type:
    • The return type is either a valid Java type (primitive or class) or void if no value is returned.
    • You can return null in a method with an object reference return type. Also, you can return any object type that can be implicitly cast to the declared return type.
    • A compile-time error is occurs, if the method return anything from a method with a void return type.
    • If the method declares a return type, every exit path out of the method must have a return statement.
    • An array is perfectly legal return type return type.
    • In a mthod with a primitive return type, you can return any value or varaible that can be implicity/expicitly converted to the declared return type.
  • Method Name: The method name must be a valid Java identifier.
  • Parameter List: The parentheses following the method name contain zero or more type/identifier pairs that make up the parameter list. Each parameter is separated by a comma. Also, there can be zero parameters.
    • Formal parameters are the parameters that are written in the method definition. These are the names that you use in your method. Formal parameters are like local variables that get an initial value at the time the method is called.
    • Actual parameters or arguments are the values that are written in the method call. The actual parameter values are copied into the formal parameters, which are then like initilialized local variables.
  • Curly Braces: The method body is contained in a set of curly braces. Normally, the method body contains a sequence of semicolon delimited Java statements that are executed sequentially. Technically, though, the method body can be empty.
    • Variables that you declare in a method are called local variables. They are created on a call stack when the method is entered, and they are destroyed when the method returns. Because objects (eg Strings and arrays) are allocated in the heap, they are never in the call stack and can be returned from the method.
    • Classes that you declare in a method are called method-local inner classes or anonymous inner classes.

Method Invocation

When you call a method outside its class, you must put an object or class name in front of it, then a dot, then the method call. For example,

    g.drawRect(10, 20, 30, 40);

This calls the drawRect method in the class of g (Graphics) with 4 int parameters. Internally there are five parameters: the Graphics object, and the four int parameters. The method can then reference all of the fields in the Graphics object without any special notation.

When you call methods which are defined in your own class, you don't need to write an object in front of them if they are working on the same fields (the same object). However, it is sometimes clearer to write this. in front of them to make it clear that you are calling the method with the current object.


Method Modifiers


Modifier Meaning
none(package) Accessible only in its package
private
Accessible only in its class(which defins it).
protected
Accessible only within its package and its subclasses
public Accessible anywhere its class is.
abstract

The method is not implemented. No body, only signature. The enclosing class is abstract (a class that contains abstract method(s) must be declared abstract).

The abstract class must be extended and the method must be implemented in the subclass except that the subclass declared as an abstract class.

final Cannot be overridden in a subclass.
native The method is implemented in another language. Platform-dependent. No body, only signature
strictfp
All floating-point computation done is strictly conforms to
the IEEE 754 standard. All values including intermediate results
must be expressed as IEEE float or double values.
It is rarely used.
static A class method that can be invoked through the class name instead of an instance of the class.
synchronized
For a static method, a lock for the class is acquired before
executing the method. For a non-static method, a lock for the specific
object instance is acquired.

Restriction rules (Please reference to Java Modifiers Matrix Table):

  • a method declaration can contain only one of the access modifiers public, protected and private
  • abstract methods cannot be declared private, static, final, native, strictfp or synchronized
  • methods cannot be declared native and strictfp simultaneously
  • abstract and native methods have no body
    • abstract void method();
    • native void method();

Types of Methods

There are two kind of methods: Instance Methods  and Static Methods.

Instance Methods

Instance methods are associated with an object and use the instance variables of that object. This is the default.

Static Methods

A static method must be explicitly defined with the modifier "static". A static method is also referred to as a class method.

Static methods use no instance variables of any object of the class they are defined in. They do not operate on objects. They do not need objects to carry out their tasks and therefore have no implicit parameter "this". The code in a static method cannot refer to this or to the fields of this because there is no class instance to serve as the receiver for such an access. Of course, a static method can invoke an instance method (or extract an instance field) of class if it explicitly specifies a receiver for the invocation.

The static methods of a class can not access any instance members of  its enclosing class, otherwise  a compile-time error will be occurs. They can access static members of a class. A common use of static variables is to define "constants". Examples from the Java library are Math.PI or Color.RED. They are qualified with the class name, so you know they are static. Any method, static or not, can access static variables. Instance variables can be accessed only by instance methods.

Static methods typically take all they data from parameters and compute something from those parameters, with no reference to variables. This is typical of methods which do some kind of generic calculation.

Static methods are useful because we occasionally need to write methods where the primary argument is either a primitive value or an object from a class that we cannot modify. For example, all of the methods in the java.lang.Math class are static methods. When you think about it, it makes a lot of sense: they just perform generic operations, such as calculating the result of one value to the power of another or the smaller of two passed values.

To invoke a static method on a Java class, use the Java invocation syntax,

ClassName.method(arg1,...,argn)

Make a call to a static method by putting a class name and a dot in front of the method call.

public class StaticMethodDemo {
  ....
  int nonstaticId;
  static int num;
  static int id;
  
  
  static void makeNumber() {
    int r = num;
    num++;
    id = r;
  }    
  public static void main(String[] args) {
  //step1.
    StaticMethodDemo.makeNumber();
    System.out.println(StaticMethodDemo.id); //Correct way
  //step2  
    StaticMethodDemo o = new StaticMethodDemo();
    System.out.println(o.nonstaticId);
    o.makeNumber();
    System.out.println(o.id);
  //step3  
    o = null;
    o.makeNumber();
    System.out.println(o.id);
  }
}

In the above example, we show you that  an object of a class may be used instead of the class name to access static methods. This is bad because it creates the impression that some instance variables in the object are used, but this isn't the case.

At the step 3, there is no exception thrown (NullPointerException) when it  was obviously invoked on a null reference. The Java compiler will ignore the instance reference but the class of the object will be used. That is why you did not have rumtime exeception.

Overriding and Hidding Methods

If a child class extends a parent class, the child inherits the methods and attributes from the parent class. The subclass may want to provide a new version of a method in the superclass. In fact, this is usually the whole reason for creating a subclass. This feature of Java enables a powerful, object-oriented technique called polymorphism.

An instance method in a subclass with the same signature and return type as an instance method in the superclass overrides the superclass's method. (Remember that a method's signature is its name and the number and the type of its arguments.) You can also override a method with the same signature that returns a subclass of the object returned by the original method. This facility is called covariant return type and introduced in J2SE 5.0 release.

Although a child class inherits all methods and attributes of their parent class, the methods and attributes must have the correct visibility in order for the child to access them.

All calls go to your new method, and not to the method by the same name in the parent class. To call the method in the parent class, as you must do in the first line of the overriding method, prefix the call with "super.". The call super.method() will invoke the method of immediate super class, but method call super.super.method() is invalid.

Methods a Subclass Cannot Override

  • A subclass cannot override methods that are declared final in the superclass (by definition, final methods cannot be overriden). If you attempt to override a final method, a compile-time error will occurs.
  • A subclass cannot override methods that are declared static in the superclass. In other words, a subclass cannot override a class method.

Methods a Subclass Must Override

Subclass must override methods that are declared abstract in the superclass, or the subclass itself must be abstract.

Hidding Methods

If a subclass defines a class method with the same signature as a class method in the superclass, the method in the subclass hides the one in the superclass. The distinction between hiding and overriding has important implications. Let's look at an example to see why. This example contains two classes. The first is Animal, which contains one instance method and one class method:

public class Animal {
    public static void hide() {
        System.out.format("The hide method in Animal.%n");
    }
    public void override() {
        System.out.format("The override method in Animal.%n");
    }
}

The second class, a subclass of Animal, is called Cat:

public class Cat extends Animal {
    public static void hide() {
        System.out.format("The hide method in Cat.%n");
    }
    public void override() {
        System.out.format("The override method in Cat.%n");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        Animal myAnimal = myCat;
        //myAnimal.hide();   //BAD STYLE
        Animal.hide();       //Better!
        myAnimal.override();
    }
}

The Cat class overrides the instance method in Animal called override and hides the class method in Animal called hide. The main method in this class creates an instance of Cat and calls the hide on the class and override on the instance.

It is considered bad style to call static methods on instances because hiding can be confusing. So it is better to use the class, for example Animal.hide or Cat.hide. The output from this program is as follows:

The hide method in Animal.
The override method in Cat.

The version of the hidden method that gets invoked is the one in the superclass, and the version of the overridden method that gets invoked is the one in the subclass. For class methods, the runtime system invokes the method defined in the compile-time type of the reference on which the method is called. In the example, the compile-time type of myAnimal is Animal. Thus, the runtime system invokes the hide method defined in Animal. For instance methods, the runtime system invokes the method defined in the runtime type of the reference on which the method is called. In the example, the runtime type of myAnimal is Cat. Thus, the runtime system invokes the override method defined in Cat.

An instance method cannot override a static method, and a static method cannot hide an instance method. The following table summarizes what happens when you define a method with the same signature as a method in a superclass.

Defining a Method with the Same Signature as a Superclass's Method
  Superclass Instance Method Superclass Static Method
Instance Method Overrides (return type must be a subtype of the return type of the superclass's method) Generates a compile-time error
Static Method Generates a compile-time error Hides

Rules for Overriding

  • Methods overriding cannot be declared more private than the super class method.
    • if the superclass method is public, the overriding method must be public
    • if the superclass method is protected, the overriding method may be protected or public
    • if the superclass method is package, the overriding method may be packagage, protected, or public
    • if the superclass methods is private, it is not inherited and overriding is not an issue
  • Any exceptions declared in overriding method must be of the same type as those thrown by the super class, or a subclass of that type.  The overriding method must not throw checked exceptions which cannot be thrown by the original method.
  • Methods declared as final cannot be overridden.
  • An overriding method can be declared as final as the keyword final only suggests that this method cannot be further overridden.
  • Methods declared as private cannot be overridden as they are not visible outside the class.
  • The return type ust be same as that of overridden method.

Overloading Methods

Each method in a class is uniquely identified by its name and parameter list. What this means is that you can have two or more methods with the exact same name, but each with a different parameter list. It is not legal to have two methods of the same name that differ only in their return types. This is a powerful feature of the Java language called method overloading. Be careful. The rules for figuring out exactly which version of a method get invoked are baroque.

Since method names typically represent an action, this allows you to define how to perform the same action on different types of inputs. Programmer-defined classes can overload methods as well. To do this simply write two methods with the same name but different argument lists.  Here is an example of overloading a method max() in order to calculate a maximum value for different combinations of inputs:

public static int max ( int x, int y ) { 
   // calculate max using two ints 
}

public static double max ( double x, double y ) {
   // calculate max using two doubles
}

Overloading is when the same method or operator can be used on many different types of data. Overloaded methods can have the same name but must have different parameter lists. The parameter lists are considered different if the order of the arguments are different. A subclass method can overload a superclass method.

Since overloading methods are essentially different methods, there is no restriction on exceptions they can throw.

The actual method called depends on the object being passed to the method. Java uses late-binding to support polymorphism; which means the decision as to which of the many methods should be used is deferred until runtime.

A difference in return type only is not sufficient to constitute an overload and is illegal. Overloaded methods may call one another simply by providing a normal method call with an appropriately formed argument list.

Whenever a subclass needs to refer to its immediate superclass, it can do so by use of the keyword ?super?. This keyword has two general forms. The first calls the superclass constructor. The second is used to access a member of the superclass that has been hidden by a member of a subclass.

  • Constructor call: The call to the superclass? constructor must always be the first statement executed inside a subclass? constructor.
  • The second form of ?super? acts like ?this?, except that it always refers to the superclass of the subclass in which it is used (e.g. super.member). This form of super is most applicable to situations in which member names of a subclass hide members by the same name in the superclass.

In a class hierarchy, constructors are called in order of derivation from superclass to subclass. Further, since super () must be the first statement executed in a subclass? constructor, this order is the same whether or not super () is used. If super () is not used, then the default or no-arguments constructor of each superclass will be executed. This is because a superclass has no knowledge of any subclass, any initialization it needs to perform is separate from and possibly prerequisite to any initialization performed by the subclass. Therefore it must be executed first.

Overloading Constructors

A constructor is a special method that is automatically run every time an instance of a class is created. Java knows that a method is a constructor because it has the same name as the class itself and no return value.

Therefore, a class can have any number of constructors provided they differ in their parameter lists. Typically, a constructor uses its arguments to initialize the new object's state. The compiler differentiates these constructors by taking into account the number of parameters in the list and their types.

Constructors are not inherited however, so if you want to get at some useful constructor from an ancestor class it is not available by default. Therefore, each of the subclasses must specifically implement any constructors it needs. Constructors can also be overloaded in similar fashion, as they are also method.

    class SuperCtor {
        SuperCtor(){}
        SuperCtor(int i) {} // compiles ok
    }

you can't overload them in subclasses as they must have the same name as the class (ie they would have to have the superclass name and would therefore not be constructors in the subclass):

    class SuperCtor {
        SuperCtor(){}
    }
    
    class SubCtor() {
        SuperCtor(){}  // compile-error
    }

The magic keyword you need to get at a constructor in an ancestor is super. This keyword can be used as if it were a method and passed the appropriate parameters to match up with the version of the parental constructor you require. The call to the superclass? constructor must always be the first statement executed inside a subclass? constructor.  

Aslo, you can call another constructor in the current class by using this as if it were a method. It must always be the first statement in the constructor.

Either this or super can be called as the first line from within a constructor, but not both.

A constructor without any parameters is known as a default constructor. When a class is defined without any constructor, the java compiler provides an implicit default constructor. The default constructor calls the default parent constructor (super()) and initializes all instance variables to default value (zero for numeric types, null for object references, and false for booleans).

The Java compiler automatically inserts the necessary constructor calls in the process of constructor chaining, or you can do it explicitly. The Java compiler inserts a call to the parent constructor (super) if you don't have a constructor call as the first statement of you constructor. 

Normally, you won't need to call the constructor for your parent class because it's automatically generated, but there are two cases where this is necessary.

  1. You want to call a parent constructor which has parameters (the automatically generated super constructor call has no parameters).
  2. There is no parameterless parent constructor because only constructors with parameters are defined in the parent class.  

Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |