Saturday, 9 May 2015

Java Classes


Now that you've seen most of the low-level details of the Java language, it's time to turn your attention to Java classes and see how Java is able to live up to its claim of being an object-oriented language. A Java class is a compile-time concept that represents a runtime object. In other words, a class is a definition or template for an object that will exist within the program. For example, if you have a class called Car, you may have a particular instance of that class that is a 1966 Volkswagen Beetle. The instances (1966 Volkswagen Beetle) of a class (Car) are known as objects. In order to define a class in Java, you would do something similar to the following:
class Car {
    // member variables
    // member methods
}

Field Declarations

Car is now an empty class. In order to make it usable and useful, you need to add some fields to the class. A field can be either a member variable or a member method. To declare member variables, all you need to do is identify the variable by type and name in the class definition, as shown in the following:
class Car {
    // these are member variables
    String manufacturer;
    String model;
    int year;
    int passengers;
}
In this example, Car has been extended to include Stringvariables for manufacturer and model, and integer variables for the year it was built and the number of passengers it can hold. From this class definition, it is then possible to create instances, or objects, at run time.

Field Access

One of the principal advantages of object-oriented programming is encapsulation. Encapsulation is the ability to define classes that hide their implementation details from other classes, exposing only their public interfaces to those other classes. Support for encapsulation in Java comes from three keywords: public, private, and protected. When you are defining a class, these field access modifiers are used to control who has access to each field in the class. By declaring a field as public, you are indicating that it is entirely accessible to all other classes. Continuing with the Carexample, to declare all of the fields as public, do the following:
class Car {
    public String manufacturer;
    public String model;
    public int year;
    public int passengers;
}
Of course, declaring everything as public doesn't exactly achieve the goal of encapsulation because it lets other classes directly access variables in the Carclass. Consider what would happen if you needed to create an instance of this class for a 1964-and-a-half Mustang. Because yearonly holds integer values, it would have to be changed to a floatso that it could hold 1964.5. If code in other classes directly accessed year, that code could conceivably break.

To restrict access to a field, use the keyword private. A class cannot access the private fields of another class. Suppose the Car class is intended for use in a used car sales application. In this case, you may want to define Car as follows in order to hide your cost for a car from potential buyers:
class Car {
    public String manufacturer;
    public String model;
    public int year;
    public int passengers;
    private float cost;
}
Finally, the keyword protectedis used to indicate that fields are accessible within the current class and all classes derived from the class, but not to other classes. The ability to derive a class from another class will be discussed later in this chapter.

Setting Initial Values

One extremely nice aspect of Java class declarations that is a deviation from C++ is the ability to specify initial values for member variables in the variable declaration. For example, because most cars will hold four passengers, it may be reasonable to default the passengers member variable to 4, as shown in the following code:
class Car {
    public String manufacturer;
    public String model;
    public int year;
    public int passengers = 4;
    private float cost;
}

Static Members

In addition to private, protected, and public members, a Java class can also have static members. A static member is one that belongs to the class itself, not to the instances of the class. Regardless of how many instances of a class have been created by a program at runtime, there will exist exactly one instance of each static member. Declaring a static member is done by adding the keyword staticto any of the other field access modifiers, as shown in the following:
class Car {
    public String manufacturer;
    public String model;
    public int year;
    public int passengers = 4;
    private float cost;
    public static int tireQty = 4;
}
In this case, the variable tireQtyhas been added and is set to 4. Because every car will have four tires, tireQtywas declared as static. Also, because we want tireQty to be accessible to other classes, it has been declared public.
It is also possible to declare member methods as static, as will be shown later in this chapter.

Member Methods

In addition to member variables, most classes will also have member methods. Because member methods, like member variables, are fields, access to them can be controlled with the public, protected, and privatemodifiers. A member method is declared according to the following syntax, in which elements enclosed in square brackets "[…]" are optional:
[methodModifiers] resultType methodName [throws exceptionList] {
    // method body
}

The methodModifiers are the familiar public, protected, and private keywords you've already seen as well as some additional modifiers. The method modifiers are described in Table 3.13.


 The resultType of a method declaration can be one of the primitive types (for example, int, float, char), another class, or void. A resultType of voidindicates that no result is passed back to the caller of the method. After the method name is given, a list of exceptions throwable by the method is given. If no exceptions are thrown by the method, this list is not necessary. 

As an example of adding a method to the Carclass, consider the following sample code:
class Car {
    public String manufacturer;
    public String model;
    public int year;
    public int passengers;
    public float CalculateSalePrice() {
        return cost * 1.5;
    }
    private float cost;
}
In this case, the Car class has had a public member method, CalculateSalePrice, added. The method returns a float, and the body of the method calculates this return value. To calculate the sale price of a car, the private member variable costis multiplied by 1.5, reflecting a markup of 50% over the amount the car was purchased for.

Overloaded Methods

The ability to overload methods is one of the biggest advantages to working in an object oriented language, and Java certainly doesn't disappoint. Overloading a method means to use the same method name for more than one method. For example, the Carclass can include two CalculateSalePricemethods, as follows:
public float CalculateSalePrice() {
    return cost * 1.5;
}

public float CalculateSalePrice(double margin) {
    return cost * (1 + margin);
}
private float cost;
In this case, the first version of CalculateSalePriceis not passed any parameters and bases the sale price on the cost plus 50% (cost * 1.5). The second version is passed a margin by which the car should be marked up in determining the car's sale price.
At runtime, Java is able to distinguish between these methods by the parameters passed to each. Because of this you can overload a method as many times as you want as long as the parameter lists of each version are unique. In other words, you could not do the following:
public float CalculateSalePrice() {
    return cost * 1.5;
}

public float CalculateSalePrice(double margin) {
    return cost * (1 + margin);
}

// this method declaration conflicts with the preceding method 
public float CalculateSalePrice(double multiplier) {
    return cost * margin;
}
private float cost;
In this situation, the last two declarations are in conflict because each is passed a double. Different parameter names are insufficient to distinguish between two versions of the same overloaded function. They must differ by at least one parameter type.

Constructors

A special type of member method is known as a constructor. A constructor is used to create new instances of a class. You can identify a constructor because it will have the same name as the class. Like any other method, a constructor can be overloaded as long as the versions are distinguishable by the parameter types passed to each. Typically, a constructor will set the member variables of an object to values appropriate for that instance. As an example, consider the following variation on the Carclass:
public class Car {
    String manufacturer;
    String model;
    int year;
    int passengers;
    float cost;

    // calculate the sale price of a car based on its cost
    public double CalculateSalePrice() {
        return cost * 1.5;
    }

    // a public constructor
    public Car(String madeBy, String name, int yr, int pass,
            float cst) {
        manufacturer = madeBy;
        model = name; 
        year = yr;
        passengers = pass; 
        cost = cst;
    }

    // create and return a string with the basic details about
    // this particular car
    public String GetStats() {
        return new String(year + " " + manufacturer + " " + model);
    }
}
A constructor, Car, has been added to this version of the Carclass. The constructor is passed five parameters that will be used as initial values for the instance variables manufacturer, model, year, passengers, and cost. The code for the constructor simply sets the five instance variables. The Car class has also received a new public member, GetStats, that creates a string that contains the basic facts about the car. By using the constructor and the new GetStatsmethod, you can now display some information about a car. For example, the following code will display "1967 VW Bug":
Car myCar = new Car("VW", "Bug", 1967, 4, 3000);
String str = myCar.GetStats();
System.out.println(str);
The new instance of the class Carwas created with the following line:
Car myCar = new Car("VW", "Bug", 1967, 4, 3000);
The use of the Java keyword newinstructs Java to create a new object of type Carby allocating memory for it and to invoke the constructor for Car whose signature matches the parameter list. In this case, Carhas only one constructor, so it is invoked and will set the instance variables to the values of the parameters. Once the variable myCargoes out of scope at the end of the function in which it is declared, the automatic memory management features of Java will detect that the memory that was allocated by newis no longer referenced and it will be released.

The this Variable

All Java classes contain a hidden member variable named this. The this member can be used at runtime to reference the object itself. One excellent use of this is in constructors. It is very common to have a set of instance variables in a class that must be set to values that are passed to a constructor. When you are doing this, it would be nice to have code that was similar to the following:
year = year;
Ideally the variable on the left could be the instance variable, and the variable on the right could be the parameter passed to the constructor. Unfortunately, I don't know of any languages that would be able to make this distinction. The typical solution most programmers have settled on is similar to the following:
public class Car {
    String manufacturer;
    String model;
    int year;
    int passengers;

    // a public constructor
    public Car(String madeBy, String name, int yr, int pass,
            float cst) {
        manufacturer = madeBy;
        model = name; 
        year = yr;
        passengers = pass; 
        cost = cst;
    }
}
Here, we've had to come up with two names for each concept: the best variable names (manufacturer, model, and so on) are used as the instance variables in the class declaration. The less satisfactory names are passed as parameters so as to distinguish them from the instance variables. The assignment statements are then very readable by Java but seem a little contrived to human readers. Java's this keyword provides a very effective solution to this problem in that the constructor can be written as follows:
public class Car {
    String manufacturer;
    String model;
    int year;
    int passengers;
    float cost;

    // calculate the sale price of a car based on its cost
    public double CalculateSalePrice() {
        return cost * 1.5;
    }

    // a public constructor
    public Car(String manufacturer, String model, int year,
            int passengers, float cost) {
        this.manufacturer = manufacturer;
        this.model = model; 
        this.year = year; 
        this.passengers = passengers;
        this.cost = cost; 
    }
}
In this case, the variables like this.yearrefer to the instance variables, whereas the unqualified variables like year refer to the constructor's parameters.

Of course, this is only one example of how you can use this. It is also frequently used as a parameter to other functions from within member methods. 

No comments:

Post a Comment