Class Methods and Constructors - Wrox Press Java Programming 24-Hour Trainer 2nd (2015)

Wrox Press Java Programming 24-Hour Trainer 2nd (2015)

Lesson 4. Class Methods and Constructors

Methods contain code for actions or functions a class can perform. Although you started working with methods in previous lessons, in this lesson you find out how to work with them in detail. You also get familiar with a special type of method called a constructor.

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 method adjustForStudents() shown inListing 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, the following method has three arguments: two of them are the int data type and one is String:

int calcLoanPayment(int amount, int numberOfMonths, String state){

// Your code goes here

}

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

calcLoanPayment(20000, 60);

the 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 method with different numbers of arguments, you need to create multiple versions of this method. For example, you can create a method that will use the state of New York as default to spare developers from providing the state as an argument. If most of the loan calculation is done for New Yorkers, such a method may be a good idea. So in addition to the method calcLoanPayment() with three arguments, you create another one with just two arguments. To avoid code duplication, only the method with three arguments implements the logic calculating payments. The method with two arguments simply calls it, adding “NY” as the third argument.

int calcLoanPayment(int amount, int numberOfMonths){

calcLoanPayment(amount, 12, “NY”);

}

Method overloading means having a class with more than one method that has the same name but different argument lists. A method can be overloaded not only in the same class but also in a descendant. For example, the class LoanCalulator can have the method 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 programmers who use these classes with a more flexible application program interface (API). Coming back to the loan-calculation example, programmers now have a choice of calling either a three- or two-argument version of this method.

In Chapter 1 you used the method println() declared in the class PrintStream (see Figure 4-1 or its description at http://docs.oracle.com/javase/8/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.

image

Figure 4-1: JavaDoc for the PrintStream class

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();

Empty parentheses in the preceding code snippet mean that this code calls a no-argument constructor on the class Tax. If you didn’t declare a constructor on a class, Java creates 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 have very little code. There you just assign initial values to class variables. In the next code snippet, a three-argument constructor is defined:

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){

// Initializing class variables

grossIncome = gi;

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, whereas in Listing 3-4 it took four lines of code to create an instance of Tax and then initialize the variables. But in the preceding code snippet you killed two birds with one stone: instantiated Tax and initialized its variables via class constructor.

Note that after defining a constructor with arguments, the rule of automatic creation of a default no-argument constructor does not apply anymore. If you need a class to have more than one constructor, and one of the constructors with no arguments, you have to explicitly write a no-argument constructor.

The preceding code snippet 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 need to use 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; for example, calcTax() in the class NJTax from Chapter 3, the JVM calls 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, to call the ancestor’s method calcTax(), you just write super.calcTax(); in the descendant:

If one class is inherited from another, each of them may have its own constructor explicitly defined. As opposed to regular class methods, a constructor of a subclass cannot override the constructor of a superclass; they even have different names. But sometimes you may need to add into the subclass’s constructor some functionality that has to be called after the ancestor’s constructor code. To avoid code duplication, just add the explicit call to the constructor of a superclass followed by additional code you want to run during instantiation of the descendant (see Listing 4-2). Invocation of the constructor of the superclass must be the first line in the constructor.

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);

// Adding code specific to descendant’s constructor

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. Besides pointing at the current object, 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.

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;

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 the Tax object 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 objectTax.

Listing 4-4: Calling a method using the keyword this as an argument

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. As with method overloading, the overloaded constructors give more choices in instantiation objects and helps avoid code duplication. 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.

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 is 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. But objects are passed by reference. The following code creates only one copy of “NJ” in memory. In Java, String objects have special rules of treatment, which are discussed in Chapter 5, but the rule still holds: Non-primitives are passed by reference.

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’m declaring another variable of type Tax and assigning 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 does not create another copy of the Tax object in memory, but copies its address to the variable t2. You still have a single instance of the Tax object, but now you have two reference variables — t and t2 — pointing at it. Until both of these variables go out of scope (something that’s explained in the next section), the object Tax is not removed from memory.

As I mentioned before, the process of removal of unused objects from memory is called garbage collection. JVM runs GC automatically.

Here’s another example of passing by reference: The code in Listing 4-5 does not create a copy of the object Tax just to pass it to the method verifyTax(). A copy of just the reference variable pointing at the Tax instance can be created inside the method SomeOtherClass.verifyTax(), pointing at the one and only instance of the class Tax.

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

Variable Scopes

Variable scope defines how long the variable lives and remains usable. If you declared the variable inside a method, it’s a local variable that goes out of scope (becomes unavailable) as soon as the method finishes its execution. For example, variables t, grossIncome, dependents, and state fromListing 4-6 are local.

If a variable is defined inside any block of code between curly braces located inside the method, the scope of the variable is limited to the code within this block. In the following code fragment the variable taxCredit has a block scope and is visible only inside the code for the case whengrossIncome < 30000.

public double calcTax() {

double stateTax=0;

if (grossIncome < 30000) {

int taxCredit = 300;

stateTax=grossIncome*0.05 - taxCredit;

}

else{

stateTax= grossIncome*0.06;

}

return stateTax;

}

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 variablesand 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 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 is shared by all instances of the same class. If the class Tax has the declaration static double grossIncome; then this variable’s value is shared by all instances of the class Tax, which doesn’t make sense in the tax calculation scenarios.

Besides, after the creation of two instances (t1 and t2), as in the preceding code, the first value of the variable (50000) is 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.

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 do 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);

Note that because you never instantiated the class WeatherReport, there is no reference variable to any object. You just use the name of the class followed by dot and the method name.

Java 8 introduced static methods in interfaces, which is covered in Lesson 6.

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.

NOTE You can download the code and resources for this “Try It” from the book’s web page at www.wrox.com/go/javaprog24hr2e. You can find them in Lesson4.zip.

Step-by-Step

1. In Eclipse IDE, create a new project named Lesson4.

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:

4. System.out.println("Preparing the tax data for customer #” +

customerCounter);

5. 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);

6. Add the static function to Tax to convert the calculated tax to euros, applying the currency-conversion rate of 1.25.

7. public static void convertToEuros(double taxInDollars){

8. System.out.println("Tax in Euros: " + taxInDollars/1.25);

}

9. Create a TestTax class and input the code from Listing 4-6. Add to this class’s main() method a line to create 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();

10. Call the method convertToEuros() twice to convert the currency, passing the calculated tax from t and t2 as an argument.

11. Run the class TestTax (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 as follows:

Preparing the tax data for customer #1

Preparing the tax data for customer #2

Tax in Euros: 13040.0

Tax in Euros: 16840.0

To get the sample files, download the content of the Chapter 4 folder from the book’s website at www.wrox.com/go/javaprog24hr2e.

TIP Please select the videos for Lesson 4 online at www.wrox.com/go/javaprog24hr2e.You will also be able to download the code and resources for this lesson from the website.