Introduction to Objects
2.2 Defining Classes and Creating Objects
The simplest Java programs consist of a single class. Within the class, we write one or more methods/functions to perform some task. Program P2.1 shows an example.
Program P2.1
//prompt for two numbers and find their sum import java.util.*;
public class Sum {
public static void main(String[] args) { Scanner in = new Scanner(System.in);
System.out.printf("Enter first number: ");
int a = in.nextInt();
System.out.printf("Enter second number: ");
int b = in.nextInt();
System.out.printf("%d + %d = %d\n", a, b, a + b);
}
} //end class Sum
The program consists of one class (ProgramP1_1) and one method (main) within the class. The class is used simply as the framework within which to write the logic of the program. We will now show how to define and use a class to create (we say instantiate) objects.
In Java, every object belongs to some class and can be created from the class definition only. Consider the following (partial) definition of the class Book:
public class Book {
private static double Discount = 0.25; //class variable private static int MinBooks = 5; //class variable private String author; // instance variable
private String title; // instance variable private double price; // instance variable private int pages; // instance variable private char binding; // instance variable private boolean inStock; // instance variable // methods to manipulate book data go here } //end class Book
The class header (the first line) consists of the following:
An optional
• access modifier; public is used in the example and will be used for most of our classes. Essentially it means that the class is available for use by any other class; it can also be extended to create subclasses. Other access modifiers are abstract and final; we won’t deal with those in this book.
The keyword
• class.
A user identifier for the name of the class;
• Book is used in the example.
The braces enclose the body of the class. In general, the body will include the declaration of the following:
Static variables (class variables); there will be one copy for the entire class—all objects will
•
share that one copy. A class variable is declared using the word static. If we omit the word static, the variable is instance.
Non-static variables (instance variables); each object created will have its own copy. It’s the
•
instance variables that comprise the data for an object.
Static methods (class methods); these are loaded once when the class is loaded and can be
•
used without creating any objects. It makes no sense for a static method to access non-static variables (which belong to objects), so Java forbids it.
Non-static methods (instance methods); these can be used
• only via an object created from the
class. It’s the non-static methods that manipulate the data (the non-static fields) in objects.
• The String class is predefined in Java. If word is String (a String object, to be precise) and we write word.toLowerCase(), we are asking that the instance method toLowerCase of the String class be applied to the String object, word. This method converts uppercase letters to lowercase in the (String) object used to invoke it.
Similarly, if
• in is a Scanner object (created when we say new Scanner...), the expression in.nextInt() applies the instance method nextInt to the object in; here, it reads the next integer from the input stream associated with in.
In the Book class, we declare two class variables (Discount and MinBooks, declared with static) and six instance variables; they are instance by default (the word static is omitted).
2.2.1 Access to Class and Instance Variables
In addition to static, a field can be declared using the optional access modifiers private, public, or protected. In the Book class, we declared all our instance variables using private. The keyword private indicates that the variable is “known” only inside the class and can be manipulated directly only by methods within the class. In other words, no method from outside the class has direct access to a private variable. However, as we will see shortly, we can provide public methods that other classes can use to set and access the values of private variables. This way, we ensure that class data can be changed only by methods within the class.
Declaring a variable public means that it can be accessed directly from outside the class. Hence, other classes can “do as they please” with a public variable. For example, if Discount is declared as public, then any other class can access it using Book.Discount and change it in any way it pleases. This is not normally encouraged since a class then loses control over its data.
For the most part, we will declare a class’s fields using private. Doing so is the first step in implementing the concept of information hiding, which is part of the philosophy of object-oriented programming. The idea is that users of an object must not be able to deal directly with the object’s data; they should do so via the object’s methods.
Declaring a variable protected means that it can be accessed directly from the class and any of its subclasses, as well as other classes in the same package. We will not use protected variables in this introduction.
If no access modifier is specified, then the variable can be accessed directly by other classes in the same package only.
A method within a class can refer to any variable (static or non-static, public or private) in the class simply by using its name. (An exception is that a static method cannot access non-static variables.) If a static variable is known outside the class (that is, not private), it is referenced by qualifying the variable with the class name, as in Book.Discount and Book.MinBooks.
From outside the class, a nonprivate instance variable can be referenced only via the object to which it belongs;
this is illustrated in the next Section. However, as indicated, good programming practice dictates that, most of the time, our variables will be declared private, so the notion of direct access from outside the class does not arise.
2.2.2 Initializing Class and Instance Variables
When the Book class is loaded, storage is immediately allocated to the class variables Discount and MinBooks; they are then assigned initial values of 0.25 and 5, respectively. The meaning behind these variables is that if five or more copies of a book are sold, then a 25 percent discount is given. Since these values apply to all books, it would be a waste of storage to store them with each book’s data, hence their declaration as static variables. All book objects will have access to the single copy of these variables. (Note, however, that if we wanted to vary these values from book to book, then they become attributes of a specific book and would have to be declared non-static.)
When the class is first loaded, no storage is allocated to the instance (non-static) variables. At this time, we have only a specification of the instance variables, but none actually exists as yet. They will come into existence when an object is created from the class. The data for an object is determined by the instance variables. When an object is
“created,” storage is allocated for all the instance variables defined in the class; each object created has its own copy of the instance variables. To create an object, we use the keyword new as in the following:
Book b;
b = new Book();
The first statement declares b as a variable of type Book. From this, we see that a class name is considered to be a type (similar to int or char) and can be used to declare variables. We say that b is an object variable of type Book.
The declaration of b does not create an object; it simply creates a variable whose value will eventually be a pointer to an object. When declared as shown, its value is undefined.
The second statement finds some available memory where a Book object can be stored, creates the object, and stores the address of the object in b. (Think of the address as the first memory location occupied by the object. If the object occupies locations 2575 to 2599, its address is 2575.) We say that b contains a reference or pointer to the object.
As a shortcut, we can declare b and create a book object in one statement, like this:
Book b = new Book();
It is a common error to think that the Book variable b can hold a Book object. It cannot; it can hold only a reference to a Book object. (In a similar manner, we should be familiar with the idea that a String variable does not hold a string but, rather, the address of where the string is stored.) However, where the distinction (between an object and a reference to the object) does not matter, we will speak as if b holds a Book object.
Once an object b is created, we can refer to its instance fields like this:
b.author b.title b.price b.pages b.binding b.inStock
However, we can do so from outside the class only if the fields are declared public. We will see later how to access the fields indirectly when they are declared private.
When an object is created, unless we say otherwise, its instance fields are initialized as follows:
Numeric fields are set to
• 0.
Character fields are set to
• '\0' (Unicode '\u0000', to be precise).
Boolean fields are set to
• false.
Object fields are set to
• null. (A variable with the value null means that it does not reference or point to anything.)
In our example, the following happens:
• b.author (of type String) is set to null; remember that String is an object type.
• b.title (of type String) is set to null.
• b.price (of type double) is set to 0.0.
• b.pages (of type int) is set to 0.
• b.binding (of type char) is set to '\0'.
• b.inStock (of type boolean) is set to false.
We could specify an initial value when we declare an instance variable. Consider this code:
public class Book {
private static double Discount = 0.25;
private static int MinBooks = 5;
author title price pages binding inStock 2575
b
2575
2599
Figure 2-1. An instance of a Book object
private String author = "No Author";
private String title;
private double price;
private int pages;
private char binding = 'P'; // for paperback private boolean inStock = true;
}
Now, when an object is created, author, binding, and inStock will be set to the specified values while title, price, and pages will assume the default values. A variable is given a default value only if no explicit value is assigned to it. Suppose we create an object b with this:
Book b = new Book();
The fields will be initialized as follows:
• author is set to "No Author". // specified in the declaration
• title is set to null. // default for (String) object type
• price is set to 0.0. // default for numeric type
• pages is set to 0. // default for numeric type
• binding is set to 'P'. // specified in the declaration
• inStock is set to true. // specified in the declaration