Chapter 4

Class Methods

Methods contain code for actions or functions a class can perform. In this lesson you’ll learn how to declare and call them.

Method Arguments

Each class method performs some functionality, such as calculating tax, placing an order, or starting the car. If a method requires some external data to perform its function, such data can be provided in the form of arguments or parameters, as in the function adjustForStudents() shown in Listing 3-5, which has one argument: stateTax.

In the method signature you need to declare the data type and the name of each argument, for example:

int calcLoanPayment(int amount, int numberOfMonths, String state){
   // Your code goes here
}

When you call a function, Java run time tries to find the function that has been declared with the specified signature. For example, if you try to call the preceding function like this:

calcLoanPayment(20000, 60);

Java compiler will give you an error complaining that no calcLoanPayment() function has been found that expects just two arguments.

Method Overloading

If you want to allow the calling of a function with different numbers of arguments, you need to create multiple versions of this function. For example, you can create a function that will use the state of New York to spare developers from providing the state as an argument. If most of the loan calculation is done for New Yorkers, such a function may be a good idea.

int calcLoanPayment(int amount, int numberOfMonths){
   // Your code for New York loan calculation goes here
}

Method overloading means having a class with more than one method having the same name but different argument lists. A method can be overloaded not only in the same class but in a descendant too. For example, the class LoanCalulator can have the function calcLoanPayment() defined with three arguments, while its descendant MyLoanCalculator may have a two-argument version of calcLoanPayment().

Why overload methods in your classes? To provide users of these classes with a more flexible application program interface (API). In Lesson 1 you use the JDK function println() declared in the class PrintStream (see Figure 4-1 or its JavaDoc description at http://java.sun.com/javase/6/docs/api/java/io/PrintStream.html). The function println() has been overloaded there to give Java developers the freedom to call “the same” method with different types of arguments. In reality they are calling different methods with the same name.

Constructors

When a program creates an instance of a class, Java invokes the class’s constructor — a special method that is called only once when the instance is being built with the operator new:

Tax t = new Tax();

Parentheses in the preceding code snippet mean that this code calls a no-argument constructor on the class Tax. Even if you didn’t declare a constructor on a class, Java will create a no-argument constructor for you.

Constructors have the following characteristics:

  • They are called when the class is being instantiated.
  • They must have the same name as the class they’re in.
  • They can’t return a value and you don’t specify the keyword void as a return type.

Typically constructors are used to assign initial values to class variables, and in the next code snippet a three-argument constructor is defined:

download.eps

Listing 4-1: Class Tax with constructor

class Tax {
    double grossIncome; // class variables
    String state;
    int dependents;
   
    // Constructor
    Tax (double gi, String st, int depen){
       grossIncome = gi;  // class variable initialization
       state = st;
       dependents=depen;
    }
}

Creating an instance of this class can look like this:

Tax t = new Tax(65000,"NJ",3);

Note the difference in the initialization of the class variables: Here you pass the values during the class instantiation via the constructor’s arguments, while in Listing 3-4 it took four lines of code to create an instance of Tax and then initialize the variables. If a constructor with arguments has been defined in a class, you can no longer use a default no-argument constructor — you have to explicitly write one if needed.

The code snippet above declares the variable t that points at an instance of the object Tax in memory. To refer to any specific field or call a method on this instance, you’ll need to use so-called dot-notation — the name of the reference variable followed by a dot and the name of the field or a method. For example,

Public static void main(){
...
Tax t = new Tax(65000,"NJ",3);
t.dependents = 4;  // changing the number of dependents from 3 to 4
...

The Keyword super

If a method is overridden in a subclass, there are two versions of the method with the same signature. If you just call a method by name, e.g. calcTax() in the class NJTax from Lesson 3, the JVM will call the overridden version of the method. Once in a while you may need to call the ancestor’s version of a method. The keyword super enables you to explicitly call the method or a constructor from the ancestor’s class, for example super.calcTax().

If one class is inherited from another, each of them may have its own constructor explicitly defined. As with any other class method, a constructor of a subclass can override the constructor of a superclass. But sometimes you may need to add into the subclass’s construction some functionality that has to be called after the ancestor’s constructor code. In this case just add the explicit call to the constructor of a superclass, as shown in Listing 4-2. Invocation of the constructor of the superclass must be the first line in the constructor.

download.eps

Listing 4-2: Calling the constructor of the ancestor

class SmallerTax extends Tax{   
    // Constructor
    SmallerTax (double gi, String st, int depen){
       super(gi,st,depen);
       System.out.println("Applying special tax rates for my friends."); 
    }
}

The Keyword this

The keyword this is useful when you need to refer to the instance of the class from its method. Review the code of the constructor from Listing 4-1. The names of the constructor’s arguments were different from the names of the class variables. But the code in Listing 4-3 shows how you can use the same variable names, both in the arguments and in the class variables. The keyword this helps to resolve name conflicts. To instruct JVM to use the instance variable grossIncome, use the following syntax:

this.grossIncome = 50000;

If there were only one grossIncome variable in the class Tax, you could simply omit the this prefix. But in Listing 4-3 the absence of the this keyword would lead to ambiguity and the instance variable would never be initialized.

download.eps

Listing 4-3: Resolving name conflicts with the this keyword

class Tax {
    double grossIncome; // class member variables
    String state;
    int dependents;
   
    // Constructor
    Tax (double grossIncome, String state, int dependents){
       this.grossIncome = grossIncome;  // instance variable initialization
       this.state = state;
       this.dependents=dependents;
    }
}

Consider a class called SomeOtherClass with a method defined as verifyTax( Tax t). As you can see, it expects an instance of Tax as an argument. Listing 4-4 shows how you can call it from the class Tax using the keyword this to pass a reference to the current instance of the class Tax.

download.eps

Listing 4-4: Calling an overloaded constructor with the keyword this

class  Tax {
     void verifyTax(){
        
        SomeOtherClass s = new SomeOtherClass();
        s.verifyTax(this);
     }
}

Here’s another use case — a class has several overloaded constructors with different numbers of arguments. You can use the this() notation to call a specific version of the constructor. In Listing 4-5 the second constructor invokes the first one.

download.eps

Listing 4-5: Calling an overloaded constructor with the keyword this

class Tax {
    double grossIncome; // class member variables
    String state;
    int dependents;
   
    // First Constructor
    Tax (double grossIncome, String state, int dependents){
       this.grossIncome = grossIncome;  // instance variable initialization
       this.state = state;
       this.dependents=dependents;
    }
   // Second Constructor
    Tax (double grossIncome, int dependents){
       this(grossIncome, "NY", dependents);     }
 
}

Passing by Value or by Reference

Calling a method with arguments enables you to pass some required data to the method. The question is how JVM passes these values to the method. Does it create a copy of a variable in a calling program and give it to the method?

The primitive values are passed by value (meaning that an extra copy will be created in memory for each variable). If you create an instance of Tax as in Listing 4-6, there will be two copies of grossIncome and two copies of the variable dependents — one in TestTax and the other one in Tax.

download.eps

Listing 4-6: The TestTax class

class TestTax{
     public static void main(String[] args){
            double grossIncome; // local variables
            String state;
            int dependents;
         
            grossIncome= 50000; 
            dependents= 2;
            state= "NJ";
 
            Tax   t = new Tax(grossIncome, state, dependents); 
 
            double yourTax = t.calcTax(); //calculating tax 
                            
           // Printing the result 
           System.out.println("Your tax is " + yourTax);
     } 
 }

In the preceding example, if you’ll be changing the value of grossIncome or dependents in the constructor of the class Tax, it won’t affect the values in the corresponding variables of the class TestTax because there will be two copies of these primitives.

Now consider another example. I’ll declare another variable of type Tax and will assign the value of t to it:

 Tax   t2 = t;

The variable t is pointing to an instance of the object Tax in memory. In other words, the variable t holds the reference (the address in memory) to an object. The code line above will not create another copy of the Tax object in memory, but will copy its address to the variable t2. Now we still have a single instance of the Tax object, but now two reference variables — t and t2 — are pointing at it. Until both of these variables will go out of scope (explained in the next section), the object Tax will not be removed from memory.

The process of removal of unused objects from memory is called garbage collection (GC). JVM runs GC automatically.

The code in Listing 4-4 passes the argument’s value differently. It seems that it passes the entire instance of the object Tax to the method verifyTax(). In reality, though, another copy of just the reference variable pointing at the Tax instance will be created in SomeOtherClass, but the instance of the class Tax will remain the same.

This means that if the code in SomeOtherClass will be changing some properties of the Tax instance, the changes will be applied to the only copy of the Tax instance and will be visible from both Tax and SomeOtherClass.

Variable Scopes

Variable scope defines how long the variable will live and remain usable. If you declared the variable inside a method, it’s a local variable that will go out of scope (become unavailable) as soon as the method finishes its execution. For example, variables t, grossIncome, dependents, and state from Listing 4-6 are local.

If variables have been declared outside the method (such as grossIncome, dependents, and state in Listing 4-1) they are class variables and can be used by any method of this class. On the other hand, the variables grossIncome, dependents, and state in Listing 4-1 are also instance variables and store instance-specific data.

You can create more than one instance of the class Tax, and each instance can have different values in its instance variables. For example, the following lines of code will create two instances of Tax, with different values for grossIncome, dependents, and state (these instance variables are initialized in the constructor):

Tax   t1 = new Tax(50000, "NY", 3 );
Tax   t2 = new Tax(65000, "TX", 4 );

The Keyword static

Java has a special keyword, static, that indicates that the class variable will be shared by all instances of the same class. If the class Tax had the declaration static double grossIncome; then this variable’s value would be shared by all instances of the class Tax, which doesn’t make sense. Besides, after the creation of two instances (t1 and t2), as in the preceding code, the first value of the variable (50000) would be overwritten with the second one (65000).

But if you introduce in Tax a class variable to count the number of its instances (think the number of customers whose taxes have been calculated), such a variable has to be declared as static, so its only version can be incremented by each instance on creation, as in Listing 4-7.

download.eps

Listing 4-7: The Tax class with the keyword static

class Tax {
    double grossIncome; // class member variables
    String state;
    int dependents;
    static int customerCounter;
   
    // Constructor
    Tax (double gi, String st, int depen){
       grossIncome = gi;  // member variable initialization
       state = st;
       dependents=depen;
       customerCounter++;   // increment the counter by one
    }
}

You can also declare methods with the static qualifier. Such methods can be called without the need to instantiate the class first. This is usually done for utility methods that don’t use any instance variables, but rather get input via the argument and return the result.

The following function converts Fahrenheit to Celsius and returns the result:

class WeatherReport{
      static double convertToCelsius(double far){
           return ((far – 32) * 5 / 9);
    }   
} 

You can call this function from another class without the need to instantiate WeatherReport first:

double centigrees=WeatherReport.convertToCelsius(98.7);

Try It

In this section you create yet another version of the Tax class with a three-argument constructor and add a utility function to convert the tax value from dollars to euros, assuming the dollar-to-euro conversion rate is 1.25.

Lesson Requirements

For this lesson you should have Eclipse IDE installed. If you prefer to use a plain text editor to code your Java programs, that’s fine too.

note.ai

You can download the code and resources for this Try It from the book’s web page at www.wrox.com. You can find them in the Lesson4 folder in the download.

Step-by-Step

1. In Eclipse IDE, create a new project named Lesson 4.

2. Create a new class called Tax (File New Class). Enter the code shown in Listing 4-7.

3. Add the following statement as the last line of the constructor of the class Tax:

System.out.println("Preparing the tax data for customer #" + customerCounter);

4. Add the method calcTax() to the class Tax and calculate tax by multiplying the gross income by 0.33 and deducting the number of dependents multiplied by one hundred:

return (grossIncome*0.33 – dependents*100);

5. Add the static function to Tax to convert the calculated tax to euros, applying the currency-conversion rate of 1.25. Print the calculated tax in euros using the function System.out.println().

6. Create a TestTax class and input the code from Listing 4-6. Add to this class yet another instance of the class Tax:

Tax   t2 = new Tax(65000, "TX", 4 ); 

Calculate the tax using the second instance of the class Tax:

double hisTax = t2.calcTax();

7. Call the method twice to convert the currency, passing the calculated tax from t and t2 as an argument.

8. Run the class TestCalc (right-click and select Run As Java Application). The Console view should display the two “Preparing the tax…” messages followed by the two messages with the calculated tax in euros.

To get the sample database files you can download Lesson 4 from the book’s website at www.wrox.com.

cd.ai

Please select Lesson 4 on the DVD with the print book, or watch online at www.wrox.com/go/fainjava to view the video that accompanies this lesson.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.173.32