Java Text - Liang (1) PDF
Document Details
Uploaded by Deleted User
Tags
Summary
This is a textbook chapter on object-oriented programming (OOP) in Java. It introduces the concepts of classes, objects, and their properties and behaviors, using examples like defining a class for circle objects, focusing on initializing and using data and methods.
Full Transcript
322 Chapter 9 Objects and Classes 9.1 Introduction Key Object-oriented programming enables you to develop large-scale software and GUIs Point effectively....
322 Chapter 9 Objects and Classes 9.1 Introduction Key Object-oriented programming enables you to develop large-scale software and GUIs Point effectively. Having learned the material in the preceding chapters, you are able to solve many program- ming problems using selections, loops, methods, and arrays. However, these Java features are not sufficient for developing graphical user interfaces and large-scale software systems. Suppose you want to develop a graphical user interface (GUI, pronounced goo-ee) as shown why OOP? in Figure 9.1. How would you program it? Button Label Text Field Check Box Radio Button Combo Box FIGURE 9.1 The GUI objects are created from classes. This chapter introduces object-oriented programming, which you can use to develop GUI and large-scale software systems. 9.2 Defining Classes for Objects Key A class defines the properties and behaviors for objects. Point Object-oriented programming (OOP) involves programming using objects. An object rep- resents an entity in the real world that can be distinctly identified. For example, a student, a VideoNote desk, a circle, a button, and even a loan can all be viewed as objects. An object has a unique Define classes and objects identity, state, and behavior. object The state of an object (also known as its properties or attributes) is represented by state of an object data fields with their current values. A circle object, for example, has a data field properties radius, which is the property that characterizes a circle. A rectangle object has the attributes data fields width and height, which are the properties that characterize a rectangle. data fields The behavior of an object (also known as its actions) is defined by methods. To behavior invoke a method on an object is to ask the object to perform an action. For exam- actions ple, you may define methods named getArea() and getPerimeter() for circle objects. A circle object may invoke getArea() to return its area and getPerim- eter() to return its perimeter. You may also define the setRadius(radius) method. A circle object can invoke this method to change its radius. class Objects of the same type are defined using a common class. A class is a template, blue- contract print, or contract that defines what an object’s data fields and methods will be. An object is an instance of a class. You can create many instances of a class. Creating an instance is referred instantiation to as instantiation. The terms object and instance are often interchangeable. The relationship instance between classes and objects is analogous to that between an apple-pie recipe and apple pies: You can make as many apple pies as you want from a single recipe. Figure 9.2 shows a class named Circle and its three objects. data field A Java class uses variables to define data fields and methods to define actions. Addition- method ally, a class provides methods of a special type, known as constructors, which are invoked to constructors create a new object. A constructor can perform any action, but constructors are designed to perform initializing actions, such as initializing the data fields of objects. Figure 9.3 shows an example of defining the class for circle objects. 9.2 Defining Classes for Objects 323 Class Name: Circle A class template Data Fields: radius is _____ Methods: getArea getPerimeter setRadius Circle Object 1 Circle Object 2 Circle Object 3 Three objects of the Circle class Data Fields: Data Fields: Data Fields: radius is 1 radius is 25 radius is 125 FIGURE 9.2 A class is a template for creating objects. class Circle { double radius = 1; Data field Circle() { } Constructors Circle(double newRadius) { radius = newRadius; } double getArea() { return radius * radius * Math.PI; } double getPerimeter() { Method return 2 * radius * Math.PI; } double setRadius(double newRadius) { radius = newRadius; } } FIGURE 9.3 A class is a construct that defines objects of the same type. The Circle class is different from all of the other classes you have seen thus far. It does not have a main method and therefore cannot be run; it is merely a definition for circle objects. The class that contains the main method will be referred to in this book, for convenience, as the main class. main class The illustration of class templates and objects in Figure 9.2 can be standardized using Unified Unified Modeling Language Modeling Language (UML) notation. This notation, as shown in Figure 9.4, is called a UML (UML) class diagram, or simply a class diagram. In the class diagram, the data field is denoted as class diagram dataFieldName: dataFieldType The constructor is denoted as ClassName(parameterName: parameterType) 324 Chapter 9 Objects and Classes UML Class Diagram Circle Class name radius: double Data fields Circle() Constructors and methods Circle(newRadius: double) getArea(): double getPerimeter(): double setRadius(newRadius: double): void circle1: Circle circle2: Circle circle3: Circle UML notation for objects radius = 1 radius = 25 radius = 125 FIGURE 9.4 Classes and objects can be represented using UML notation. The method is denoted as methodName(parameterName: parameterType): returnType 9.3 Example: Defining Classes and Creating Objects Classes are definitions for objects and objects are created from classes. Key Point This section gives two examples of defining classes and uses the classes to create objects. Listing 9.1 is a program that defines the Circle class and uses it to create objects. The pro- gram constructs three circle objects with radius 1, 25, and 125 and displays the radius and area of each of the three circles. It then changes the radius of the second object to 100 and displays its new radius and area. Note avoid naming conflicts To avoid a naming conflict with several enhanced versions of the Circle class intro- duced later in the chapter, the Circle class in this example is named SimpleCircle. For simplicity, we will still refer to the class in the text as Circle. LISTING 9.1 TestSimpleCircle.java main class 1 public class TestSimpleCircle { 2 main method 3 public static void main(String[] args) { 4 // Create a circle with radius 1 create object 5 SimpleCircle circle1 = new SimpleCircle(); 6 System.out.println("The area of the circle of radius " 7 + circle1.radius + " is " + circle1.getArea()); 8 9 // Create a circle with radius 25 create object 10 SimpleCircle circle2 = new SimpleCircle(25); 11 System.out.println("The area of the circle of radius " 12 + circle2.radius + " is " + circle2.getArea()); 13 14 // Create a circle with radius 125 create object 15 SimpleCircle circle3 = new SimpleCircle(125); 16 System.out.println("The area of the circle of radius " 17 + circle3.radius + " is " + circle3.getArea()); 18 19 // Modify circle radius 20 circle2.radius = 100; // or circle2.setRadius(100) 21 System.out.println("The area of the circle of radius " 22 + circle2.radius + " is " + circle2.getArea()); 9.3 Example: Defining Classes and Creating Objects 325 23 } 24 } 25 26 // Define the circle class with two constructors 27 class SimpleCircle { class SimpleCircle 28 double radius; data field 29 30 31 SimpleCircle() { no-arg constructor 32 radius = 1; 33 } 34 35 36 SimpleCircle(double newRadius) { second constructor 37 radius = newRadius; 38 } 39 40 41 double getArea() { getArea 42 return radius * radius * Math.PI; 43 } 44 45 46 double getPerimeter() { getPerimeter 47 return 2 * radius * Math.PI; 48 } 49 50 51 void setRadius(double newRadius) { setRadius 52 radius = newRadius; 53 } 54 } The area of the circle of radius 1.0 is 3.141592653589793 The area of the circle of radius 25.0 is 1963.4954084936207 The area of the circle of radius 125.0 is 49087.385212340516 The area of the circle of radius 100.0 is 31415.926535897932 The program contains two classes. The first of these, TestSimpleCircle, is the main class. Its sole purpose is to test the second class, SimpleCircle. Such a program that uses the class is often referred to as a client of the class. When you run the program, the Java runtime system client invokes the main method in the main class. You can put the two classes into one file, but only one class in the file can be a public class. public class Furthermore, the public class must have the same name as the file name. Therefore, the file name is TestSimpleCircle.java, since TestSimpleCircle is public. Each class in the source code is compiled into a.class file. When you compile TestSimpleCircle.java, two class files TestSimpleCircle.class and SimpleCircle.class are generated, as shown in Figure 9.5. // File TestSimpleCircle.java generates TestSimpleCircle.class public class TestSimpleCircle { … Java } compiled Compiler class SimpleCircle { by … generates SimpleCircle.class } FIGURE 9.5 Each class in the source code file is compiled into a.class file. 326 Chapter 9 Objects and Classes The main class contains the main method (line 3) that creates three objects. As in creating an array, the new operator is used to create an object from the constructor: new SimpleCircle() creates an object with radius 1 (line 5), new SimpleCircle(25) creates an object with radius 25 (line 10), and new SimpleCircle(125) creates an object with radius 125 (line 15). These three objects (referenced by circle1, circle2, and circle3) have different data but the same methods. Therefore, you can compute their respective areas by using the getArea() method. The data fields can be accessed via the reference of the object using circle1.radius, circle2.radius, and circle3.radius, respectively. The object can invoke its method via the reference of the object using circle1.getArea(), circle2.getArea(), and circle3.getArea(), respectively. These three objects are independent. The radius of circle2 is changed to 100 in line 20. The object’s new radius and area are displayed in lines 21–22. There are many ways to write Java programs. For instance, you can combine the two classes in the example into one, as shown in Listing 9.2. LISTING 9.2 SimpleCircle.java 1 public class SimpleCircle { 2 main method 3 public static void main(String[] args) { 4 // Create a circle with radius 1 5 SimpleCircle circle1 = new SimpleCircle(); 6 System.out.println("The area of the circle of radius " 7 + circle1.radius + " is " + circle1.getArea()); 8 9 // Create a circle with radius 25 10 SimpleCircle circle2 = new SimpleCircle(25); 11 System.out.println("The area of the circle of radius " 12 + circle2.radius + " is " + circle2.getArea()); 13 14 // Create a circle with radius 125 15 SimpleCircle circle3 = new SimpleCircle(125); 16 System.out.println("The area of the circle of radius " 17 + circle3.radius + " is " + circle3.getArea()); 18 19 // Modify circle radius 20 circle2.radius = 100; 21 System.out.println("The area of the circle of radius " 22 + circle2.radius + " is " + circle2.getArea()); 23 } 24 data field 25 double radius; 26 27 no-arg constructor 28 SimpleCircle() { 29 radius = 1; 30 } 31 32 second constructor 33 SimpleCircle(double newRadius) { 34 radius = newRadius; 35 } 36 37 method 38 double getArea() { 39 return radius * radius * Math.PI; 40 } 41 9.3 Example: Defining Classes and Creating Objects 327 42 43 double getPerimeter() { 44 return 2 * radius * Math.PI; 45 } 46 47 48 void setRadius(double newRadius) { 49 radius = newRadius; 50 } 51 } Since the combined class has a main method, it can be executed by the Java interpreter. The main method is the same as that in Listing 9.1. This demonstrates that you can test a class by simply adding a main method in the same class. As another example, consider television sets. Each TV is an object with states (current channel, current volume level, power on or off) and behaviors (change channels, adjust vol- ume, turn on/off). You can use a class to model TV sets. The UML diagram for the class is shown in Figure 9.6. TV channel: int The current channel (1 to 120) of this TV. volumeLevel: int The current volume level (1 to 7) of this TV. on: boolean Indicates whether this TV is on/off. The + sign indicates public modifier +TV() Constructs a default TV object. +turnOn(): void Turns on this TV. +turnOff(): void Turns off this TV. +setChannel(newChannel: int): void Sets a new channel for this TV. +setVolume(newVolumeLevel: int): void Sets a new volume level for this TV. +channelUp(): void Increases the channel number by 1. +channelDown(): void Decreases the channel number by 1. +volumeUp(): void Increases the volume level by 1. +volumeDown(): void Decreases the volume level by 1. FIGURE 9.6 The TV class models TV sets. Listing 9.3 gives a program that defines the TV class. LISTING 9.3 TV.java 1 public class TV { 2 int channel = 1; // Default channel is 1 data fields 3 int volumeLevel = 1; // Default volume level is 1 4 boolean on = false; // TV is off 5 6 public TV() { constructor 7 } 8 9 public void turnOn() { turn on TV 10 on = true; 11 } 12 13 public void turnOff() { turn off TV 328 Chapter 9 Objects and Classes 14 on = false; 15 } 16 set a new channel 17 public void setChannel(int newChannel) { 18 if (on && newChannel >= 1 && newChannel = 1 && newVolumeLevel 1) 34 channel—–; 35 } 36 increase volume 37 public void volumeUp() { 38 if (on && volumeLevel < 7) 39 volumeLevel++; 40 } 41 decrease volume 42 public void volumeDown() { 43 if (on && volumeLevel > 1) 44 volumeLevel—–; 45 } 46 } The constructor and methods in the TV class are defined public so they can be accessed from other classes. Note that the channel and volume level are not changed if the TV is not on. Before either of these is changed, its current value is checked to ensure that it is within the correct range. Listing 9.4 gives a program that uses the TV class to create two objects. LISTING 9.4 TestTV.java 1 public class TestTV { main method 2 public static void main(String[] args) { create a TV 3 TV tv1 = new TV(); turn on 4 tv1.turnOn(); set a new channel 5 tv1.setChannel(30); set a new volume 6 tv1.setVolume(3); 7 create a TV 8 TV tv2 = new TV(); turn on 9 tv2.turnOn(); increase channel 10 tv2.channelUp(); 11 tv2.channelUp(); increase volume 12 tv2.volumeUp(); 13 display state 14 System.out.println("tv1's channel is " + tv1.channel 15 + " and volume level is " + tv1.volumeLevel); 16 System.out.println("tv2's channel is " + tv2.channel 17 + " and volume level is " + tv2.volumeLevel); 18 } 19 } 9.4 Constructing Objects Using Constructors 329 tv1's channel is 30 and volume level is 3 tv2's channel is 3 and volume level is 2 The program creates two objects in lines 3 and 8 and invokes the methods on the objects to perform actions for setting channels and volume levels and for increasing channels and vol- umes. The program displays the state of the objects in lines 14–17. The methods are invoked using syntax such as tv1.turnOn() (line 4). The data fields are accessed using syntax such as tv1.channel (line 14). These examples have given you a glimpse of classes and objects. You may have many questions regarding constructors, objects, reference variables, accessing data fields, and invoking object’s methods. The sections that follow discuss these issues in detail. 9.1 9.2 Describe the relationship between an object and its defining class. How do you define a class? ✓ Check Point 9.3 How do you declare an object’s reference variable? 9.4 How do you create an object? 9.4 Constructing Objects Using Constructors A constructor is invoked to create an object using the new operator. Key Constructors are a special kind of method. They have three peculiarities: Point A constructor must have the same name as the class itself. constructor’s name Constructors do not have a return type—not even void. no return type Constructors are invoked using the new operator when an object is created. new operator Constructors play the role of initializing objects. The constructor has exactly the same name as its defining class. Like regular methods, constructors can be overloaded (i.e., multiple constructors can have the same name but differ- overloaded constructors ent signatures), making it easy to construct objects with different initial data values. It is a common mistake to put the void keyword in front of a constructor. For example, public void Circle() { no void } In this case, Circle() is a method, not a constructor. Constructors are used to construct objects. To construct an object from a class, invoke a constructing objects constructor of the class using the new operator, as follows: new ClassName(arguments); For example, new Circle() creates an object of the Circle class using the first construc- tor defined in the Circle class, and new Circle(25) creates an object using the second constructor defined in the Circle class. A class normally provides a constructor without arguments (e.g., Circle()). Such a con- structor is referred to as a no-arg or no-argument constructor. no-arg constructor A class may be defined without constructors. In this case, a public no-arg constructor with an empty body is implicitly defined in the class. This constructor, called a default constructor, default constructor is provided automatically only if no constructors are explicitly defined in the class. 9.5 9.6 What are the differences between constructors and methods? When will a class have a default constructor? ✓ Check Point 330 Chapter 9 Objects and Classes 9.5 Accessing Objects via Reference Variables Key An object’s data and methods can be accessed through the dot (.) operator via the Point object’s reference variable. Newly created objects are allocated in the memory. They can be accessed via reference variables. 9.5.1 Reference Variables and Reference Types reference variable Objects are accessed via the object’s reference variables, which contain references to the objects. Such variables are declared using the following syntax: ClassName objectRefVar; reference type A class is essentially a programmer-defined type. A class is a reference type, which means that a variable of the class type can reference an instance of the class. The following statement declares the variable myCircle to be of the Circle type: Circle myCircle; The variable myCircle can reference a Circle object. The next statement creates an object and assigns its reference to myCircle: myCircle = new Circle(); You can write a single statement that combines the declaration of an object reference variable, the creation of an object, and the assigning of an object reference to the variable with the fol- lowing syntax: ClassName objectRefVar = new ClassName(); Here is an example: Circle myCircle = new Circle(); The variable myCircle holds a reference to a Circle object. Note object vs. object reference An object reference variable that appears to hold an object actually contains a reference variable to that object. Strictly speaking, an object reference variable and an object are different, but most of the time the distinction can be ignored. Therefore, it is fine, for simplicity, to say that myCircle is a Circle object rather than use the longer-winded description that myCircle is a variable that contains a reference to a Circle object. Note array object Arrays are treated as objects in Java. Arrays are created using the new operator. An array variable is actually a variable that contains a reference to an array. 9.5.2 Accessing an Object’s Data and Methods In OOP terminology, an object’s member refers to its data fields and methods. After an object dot operator (.) is created, its data can be accessed and its methods can be invoked using the dot operator (.), also known as the object member access operator: objectRefVar.dataField references a data field in the object. objectRefVar.method(arguments) invokes a method on the object. 9.5 Accessing Objects via Reference Variables 331 For example, myCircle.radius references the radius in myCircle, and myCircle.getArea() invokes the getArea method on myCircle. Methods are invoked as operations on objects. The data field radius is referred to as an instance variable, because it is dependent on instance variable a specific instance. For the same reason, the method getArea is referred to as an instance instance method method, because you can invoke it only on a specific instance. The object on which an instance method is invoked is called a calling object. calling object Caution Recall that you use Math.methodName(arguments) (e.g., Math.pow(3, 2.5)) to invoke a method in the Math class. Can you invoke getArea() using invoking methods Circle.getArea()? The answer is no. All the methods in the Math class are static methods, which are defined using the static keyword. However, getArea() is an instance method, and thus nonstatic. It must be invoked from an object using objectRefVar.methodName(arguments) (e.g., myCircle.getArea()). Further explanation is given in Section 9.7, Static Variables, Constants, and Methods. Note Usually you create an object and assign it to a variable, and then later you can use the variable to reference the object. Occasionally an object does not need to be referenced later. In this case, you can create an object without explicitly assigning it to a variable using the syntax: new Circle(); or System.out.println("Area is " + new Circle(5).getArea()); The former statement creates a Circle object. The latter creates a Circle object and invokes its getArea method to return its area. An object created in this way is known as an anonymous object. anonymous object 9.5.3 Reference Data Fields and the null Value The data fields can be of reference types. For example, the following Student class contains reference data fields a data field name of the String type. String is a predefined Java class. class Student { String name; // name has the default value null int age; // age has the default value 0 boolean isScienceMajor; // isScienceMajor has default value false char gender; // gender has default value '\u0000' } If a data field of a reference type does not reference any object, the data field holds a special Java value, null. null is a literal just like true and false. While true and false are null value Boolean literals, null is a literal for a reference type. The default value of a data field is null for a reference type, 0 for a numeric type, false default field values for a boolean type, and \u0000 for a char type. However, Java assigns no default value to a local variable inside a method. The following code displays the default values of the data fields name, age, isScienceMajor, and gender for a Student object: class Test { public static void main(String[] args) { Student student = new Student(); System.out.println("name? " + student.name); 332 Chapter 9 Objects and Classes System.out.println("age? " + student.age); System.out.println("isScienceMajor? " + student.isScienceMajor); System.out.println("gender? " + student.gender); } } The following code has a compile error, because the local variables x and y are not initialized: class Test { public static void main(String[] args) { int x; // x has no default value String y; // y has no default value System.out.println("x is " + x); System.out.println("y is " + y); } } Caution NullPointerException NullPointerException is a common runtime error. It occurs when you invoke a method on a reference variable with a null value. Make sure you assign an object reference to the variable before invoking the method through the reference variable (See Checkpoint Question 9.11c). 9.5.4 Differences between Variables of Primitive Types and Reference Types Every variable represents a memory location that holds a value. When you declare a variable, you are telling the compiler what type of value the variable can hold. For a variable of a primi- tive type, the value is of the primitive type. For a variable of a reference type, the value is a reference to where an object is located. For example, as shown in Figure 9.7, the value of int variable i is int value 1, and the value of Circle object c holds a reference to where the contents of the Circle object are stored in memory. When you assign one variable to another, the other variable is set to the same value. For a variable of a primitive type, the real value of one variable is assigned to the other variable. For a variable of a reference type, the reference of one variable is assigned to the other vari- able. As shown in Figure 9.8, the assignment statement i = j copies the contents of j into i Created using new Circle() Primitive type int i = 1 i 1 Object type Circle c c reference c: Circle radius = 1 FIGURE 9.7 A variable of a primitive type holds a value of the primitive type, and a variable of a reference type holds a reference to where an object is stored in memory. Primitive type assignment i = j Before: After: i 1 i 2 j 2 j 2 FIGURE 9.8 Primitive variable j is copied to variable i. 9.5 Accessing Objects via Reference Variables 333 for primitive variables. As shown in Figure 9.9, the assignment statement c1 = c2 copies the reference of c2 into c1 for reference variables. After the assignment, variables c1 and c2 refer to the same object. Object type assignment c1 = c2 Before: After: c1 c1 c2 c2 c2: Circle c1: Circle c2: Circle c1: Circle radius = 9 radius = 5 radius = 9 radius = 5 FIGURE 9.9 Reference variable c2 is copied to variable c1. Note As illustrated in Figure 9.9, after the assignment statement c1 = c2, c1 points to the same object referenced by c2. The object previously referenced by c1 is no longer useful and therefore is now known as garbage. Garbage occupies memory space, so the Java garbage runtime system detects garbage and automatically reclaims the space it occupies. This process is called garbage collection. garbage collection Tip If you know that an object is no longer needed, you can explicitly assign null to a refer- ence variable for the object. The JVM will automatically collect the space if the object is not referenced by any reference variable. 9.7 9.8 Which operator is used to access a data field or invoke a method from an object? What is an anonymous object? ✓ Check Point 9.9 What is NullPointerException? 9.10 Is an array an object or a primitive type value? Can an array contain elements of an object type? Describe the default value for the elements of an array. 9.11 What is wrong with each of the following programs? 1 public class ShowErrors { 1 public class ShowErrors { 2 public static void main(String[] args) { 2 public static void main(String[] args) { 3 ShowErrors t = new ShowErrors(5); 3 ShowErrors t = new ShowErrors(); 4 } 4 t.x(); 5 } 5 } 6 } (a) (b) 1 public class ShowErrors { 1 public class ShowErrors { 2 public void method1() { 2 public static void main(String[] args) { 3 Circle c; 3 C c = new C(5.0); 4 System.out.println("What is radius " 4 System.out.println(c.value); 5 + c.getRadius()); 5 } 6 c = new Circle(); 6 } 7 } 7 8 } 8 class C { 9 int value = 2; 10 } (c) (d) 334 Chapter 9 Objects and Classes 9.12 What is wrong in the following code? 1 class Test { 2 public static void main(String[] args) { 3 A a = new A(); 4 a.print(); 5 } 6 } 7 8 class A { 9 String s; 10 11 A(String newS) { 12 s = newS; 13 } 14 15 public void print() { 16 System.out.print(s); 17 } 18 } 9.13 What is the output of the following code? public class A { boolean x; public static void main(String[] args) { A a = new A(); System.out.println(a.x); } } 9.6 Using Classes from the Java Library The Java API contains a rich set of classes for developing Java programs. Key Point Listing 9.1 defined the SimpleCircle class and created objects from the class. You will frequently use the classes in the Java library to develop programs. This section gives some examples of the classes in the Java library. VideoNote Use classes 9.6.1 The Date Class In Listing 2.7, ShowCurrentTime.java, you learned how to obtain the current time using System.currentTimeMillis(). You used the division and remainder operators to extract the current second, minute, and hour. Java provides a system-independent encapsulation of java.util.Date class date and time in the java.util.Date class, as shown in Figure 9.10. java.util.Date +Date() Constructs a Date object for the current time. +Date(elapseTime: long) Constructs a Date object for a given time in milliseconds elapsed since January 1, 1970, GMT. +toString(): String Returns a string representing the date and time. +getTime(): long Returns the number of milliseconds since January 1, 1970, GMT. +setTime(elapseTime: long): void Sets a new elapse time in the object. FIGURE 9.10 A Date object represents a specific date and time. 9.6 Using Classes from the Java Library 335 You can use the no-arg constructor in the Date class to create an instance for the cur- rent date and time, the getTime() method to return the elapsed time since January 1, 1970, GMT, and the toString() method to return the date and time as a string. For example, the following code java.util.Date date = new java.util.Date(); create object System.out.println("The elapsed time since Jan 1, 1970 is " + date.getTime() + " milliseconds"); get elapsed time System.out.println(date.toString()); invoke toString displays the output like this: The elapsed time since Jan 1, 1970 is 1324903419651 milliseconds Mon Dec 26 07:43:39 EST 2011 The Date class has another constructor, Date(long elapseTime), which can be used to construct a Date object for a given time in milliseconds elapsed since January 1, 1970, GMT. 9.6.2 The Random Class You have used Math.random() to obtain a random double value between 0.0 and 1.0 (excluding 1.0). Another way to generate random numbers is to use the java.util.Random class, as shown in Figure 9.11, which can generate a random int, long, double, float, and boolean value. java.util.Random +Random() Constructs a Random object with the current time as its seed. +Random(seed: long) Constructs a Random object with a specified seed. +nextInt(): int Returns a random int value. +nextInt(n: int): int Returns a random int value between 0 and n (excluding n). +nextLong(): long Returns a random long value. +nextDouble(): double Returns a random double value between 0.0 and 1.0 (excluding 1.0). +nextFloat(): float Returns a random float value between 0.0F and 1.0F (excluding 1.0F). +nextBoolean(): boolean Returns a random boolean value. FIGURE 9.11 A Random object can be used to generate random values. When you create a Random object, you have to specify a seed or use the default seed. A seed is a number used to initialize a random number generator. The no-arg constructor cre- ates a Random object using the current elapsed time as its seed. If two Random objects have the same seed, they will generate identical sequences of numbers. For example, the following code creates two Random objects with the same seed, 3. Random random1 = new Random(3); System.out.print("From random1: "); for (int i = 0; i < 10; i++) System.out.print(random1.nextInt(1000) + " "); Random random2 = new Random(3); System.out.print("\nFrom random2: "); for (int i = 0; i < 10; i++) System.out.print(random2.nextInt(1000) + " "); 336 Chapter 9 Objects and Classes The code generates the same sequence of random int values: From random1: 734 660 210 581 128 202 549 564 459 961 From random2: 734 660 210 581 128 202 549 564 459 961 Note same sequence The ability to generate the same sequence of random values is useful in software testing and many other applications. In software testing, often you need to reproduce the test cases from a fixed sequence of random numbers. 9.6.3 The Point2D Class Java API has a conveninent Point2D class in the javafx.geometry package for represent- ing a point in a two-dimensional plane. The UML diagram for the class is shown in Figure 9.12. javafx.geometry.Point2D +Point2D(x: double, y: double) Constructs a Point2D object with the specified x- and y-coordinates. +distance(x: double, y: double): double Returns the distance between this point and the specified point (x, y). +distance(p: Point2D): double Returns the distance between this point and the specified point p. +getX(): double Returns the x-coordinate from this point. +getY(): double Returns the y-coordinate from this point. +toString(): String Returns a string representation for the point. FIGURE 9.12 A Point2D object represents a point with x- and y-coordinates. You can create a Point2D object for a point with the specified x- and y-coordinates, use the distance method to compute the distance from this point to another point, and use the toString() method to return a string representation of the point. Lisitng 9.5 gives an exam- ple of using this class. LISTING 9.5 TestPoint2D.java 1 import java.util.Scanner; 2 import javafx.geometry.Point2D; 3 4 public class TestPoint2D { 5 public static void main(String[] args) { 6 Scanner input = new Scanner(System.in); 7 8 System.out.print("Enter point1's x-, y-coordinates: "); 9 double x1 = input.nextDouble(); 10 double y1 = input.nextDouble(); 11 System.out.print("Enter point2's x-, y-coordinates: "); 12 double x2 = input.nextDouble(); 13 double y2 = input.nextDouble(); 14 create an object 15 Point2D p1 = new Point2D(x1, y1); 16 Point2D p2 = new Point2D(x2, y2); invoke toString() 17 System.out.println("p1 is " + p1.toString()); 18 System.out.println("p2 is " + p2.toString()); 19 System.out.println("The distance between p1 and p2 is " + get distance 20 p1.distance(p2)); 21 } 22 } 9.7 Static Variables, Constants, and Methods 337 Enter point1's x-, y-coordinates: 1.5 5.5 Enter point2's x-, y-coordinates: -5.3 -4.4 p1 is Point2D [x = 1.5, y = 5.5] p2 is Point2D [x = -5.3, y = -4.4] The distance between p1 and p2 is 12.010412149464313 This program creates two objects of the Point2D class (lines 15–16). The toString() method returns a string that describes the object (lines 17–18). Invoking p1.distance(p2) returns the distance between the two points (line 20). 9.14 9.15 How do you create a Date for the current time? How do you display the current time? How do you create a Point2D? Suppose p1 and p2 are two instances of Point2D? How do you obtain the distance between the two points? ✓ Check Point 9.16 Which packages contain the classes Date, Random, Point2D, System, and Math? 9.7 Static Variables, Constants, and Methods A static variable is shared by all objects of the class. A static method cannot access Key instance members of the class. Point The data field radius in the circle class is known as an instance variable. An instance vari- Static vs. instance able is tied to a specific instance of the class; it is not shared among objects of the same class. instance variable For example, suppose that you create the following objects: Circle circle1 = new Circle(); VideoNote Circle circle2 = new Circle(5); Static vs. instance The radius in circle1 is independent of the radius in circle2 and is stored in a differ- ent memory location. Changes made to circle1’s radius do not affect circle2’s radius, and vice versa. If you want all the instances of a class to share data, use static variables, also known as static variable class variables. Static variables store values for the variables in a common memory location. Because of this common location, if one object changes the value of a static variable, all objects of the same class are affected. Java supports static methods as well as static variables. Static methods can be called without creating an instance of the class. static method Let’s modify the Circle class by adding a static variable numberOfObjects to count the number of circle objects created. When the first object of this class is created, numberOfOb- jects is 1. When the second object is created, numberOfObjects becomes 2. The UML of the new circle class is shown in Figure 9.13. The Circle class defines the instance vari- able radius and the static variable numberOfObjects, the instance methods getRadius, setRadius, and getArea, and the static method getNumberOfObjects. (Note that static variables and methods are underlined in the UML class diagram.) To declare a static variable or define a static method, put the modifier static in the variable or method declaration. The static variable numberOfObjects and the static method getNumberOfObjects() can be declared as follows: static int numberOfObjects; declare static variable static int getNumberObjects() { define static method return numberOfObjects; } 338 Chapter 9 Objects and Classes UML Notation: underline: static variables or methods instantiate circle1: Circle Memory radius = 1 1 radius After two Circle Circle numberOfObjects = 2 Objects were created, numberOfObjects radius: double is 2. numberOfObjects: int 2 numberOfObjects getNumberOfObjects(): int getArea(): double instantiate circle2: Circle radius = 5 5 radius numberOfObjects = 2 FIGURE 9.13 Instance variables belong to the instances and have memory storage independent of one another. Static variables are shared by all the instances of the same class. declare constant Constants in a class are shared by all objects of the class. Thus, constants should be declared as final static. For example, the constant PI in the Math class is defined as: final static double PI = 3.14159265358979323846; The new circle class, named CircleWithStaticMembers, is defined in Listing 9.6: LISTING 9.6 CircleWithStaticMembers.java 1 public class CircleWithStaticMembers { 2 3 double radius; 4 5 static variable 6 static int numberOfObjects = 0; 7 8 9 CircleWithStaticMembers() { 10 radius = 1; increase by 1 11 numberOfObjects++; 12 } 13 14 15 CircleWithStaticMembers(double newRadius) { 16 radius = newRadius; increase by 1 17 numberOfObjects++; 18 } 19 20 static method 21 static int getNumberOfObjects() { 22 return numberOfObjects; 23 } 24 25 26 double getArea() { 27 return radius * radius * Math.PI; 28 } 29 } Method getNumberOfObjects() in CircleWithStaticMembers is a static method. All the methods in the Math class are static. The main method is static, too. 9.7 Static Variables, Constants, and Methods 339 Instance methods (e.g., getArea()) and instance data (e.g., radius) belong to instances and can be used only after the instances are created. They are accessed via a reference variable. Static methods (e.g., getNumberOfObjects()) and static data (e.g., numberOfObjects) can be accessed from a reference variable or from their class name. The program in Listing 9.7 demonstrates how to use instance and static variables and meth- ods and illustrates the effects of using them. LISTING 9.7 TestCircleWithStaticMembers.java 1 public class TestCircleWithStaticMembers { 2 3 public static void main(String[] args) { 4 System.out.println("Before creating objects"); 5 System.out.println("The number of Circle objects is " + 6 CircleWithStaticMembers.numberOfObjects); static variable 7 8 // Create c1 9 CircleWithStaticMembers c1 = new CircleWithStaticMembers(); 10 11 // Display c1 BEFORE c2 is created 12 System.out.println("\nAfter creating c1"); 13 System.out.println("c1: radius (" + c1.radius + instance variable 14 ") and number of Circle objects (" + 15 c1.numberOfObjects + ")"); static variable 16 17 // Create c2 18 CircleWithStaticMembers c2 = new CircleWithStaticMembers(5); 19 20 // Modify c1 21 c1.radius = 9; instance variable 22 23 // Display c1 and c2 AFTER c2 was created 24 System.out.println("\nAfter creating c2 and modifying c1"); 25 System.out.println("c1: radius (" + c1.radius + 26 ") and number of Circle objects (" + 27 c1.numberOfObjects + ")"); static variable 28 System.out.println("c2: radius (" + c2.radius + 29 ") and number of Circle objects (" + 30 c2.numberOfObjects + ")"); static variable 31 } 32 } Before creating objects The number of Circle objects is 0 After creating c1 c1: radius (1.0) and number of Circle objects (1) After creating c2 and modifying c1 c1: radius (9.0) and number of Circle objects (2) c2: radius (5.0) and number of Circle objects (2) When you compile TestCircleWithStaticMembers.java, the Java compiler automati- cally compiles CircleWithStaticMembers.java if it has not been compiled since the last change. Static variables and methods can be accessed without creating objects. Line 6 displays the number of objects, which is 0, since no objects have been created. 340 Chapter 9 Objects and Classes The main method creates two circles, c1 and c2 (lines 9, 18). The instance variable radius in c1 is modified to become 9 (line 21). This change does not affect the instance variable radius in c2, since these two instance variables are independent. The static vari- able numberOfObjects becomes 1 after c1 is created (line 9), and it becomes 2 after c2 is created (line 18). Note that PI is a constant defined in Math, and Math.PI references the con- stant. c1.numberOfObjects (line 27) and c2.numberOfObjects (line 30) are better replaced by CircleWithStaticMembers.numberOfObjects. This improves readability, because other programmers can easily recognize the static variable. You can also replace CircleWithStaticMembers.numberOfObjects with CircleWithStaticMembers. getNumberOfObjects(). Tip use class name Use ClassName.methodName(arguments) to invoke a static method and ClassName.staticVariable to access a static variable. This improves readability, because this makes the static method and data easy to spot. An instance method can invoke an instance or static method and access an instance or static data field. A static method can invoke a static method and access a static data field. However, a static method cannot invoke an instance method or access an instance data field, since static methods and static data fields don’t belong to a particular object. The relationship between static and instance members is summarized in the following diagram: invoke invoke An instance method An instance method access access An instance data field An instance data field An instance method invoke A static method invoke A static method A static method access access A static data field A static data field For example, the following code is wrong. 1 public class A { 2 int i = 5; 3 static int k = 2; 4 5 public static void main(String[] args) { 6 int j = i; // Wrong because i is an instance variable 7 m1(); // Wrong because m1() is an instance method 8 } 9 10 public void m1() { 11 // Correct since instance and static variables and methods 12 // can be used in an instance method 13 i = i + k + m2(i, k); 14 } 15 16 public static int m2(int i, int j) { 17 return (int)(Math.pow(i, j)); 18 } 19 } 9.7 Static Variables, Constants, and Methods 341 Note that if you replace the preceding code with the following new code, the program would be fine, because the instance data field i and method m1 are now accessed from an object a (lines 7–8): 1 public class A { 2 int i = 5; 3 static int k = 2; 4 5 public static void main(String[] args) { 6 A a = new A(); 7 int j = a.i; // OK, a.i accesses the object's instance variable 8 a.m1(); // OK. a.m1() invokes the object's instance method 9 } 10 11 public void m1() { 12 i = i + k + m2(i, k); 13 } 14 15 public static int m2(int i, int j) { 16 return (int)(Math.pow(i, j)); 17 } 18 } Design Guide How do you decide whether a variable or a method should be an instance one or a instance or static? static one? A variable or a method that is dependent on a specific instance of the class should be an instance variable or method. A variable or a method that is not dependent on a specific instance of the class should be a static variable or method. For example, every circle has its own radius, so the radius is dependent on a specific circle. Therefore, radius is an instance variable of the Circle class. Since the getArea method is dependent on a specific circle, it is an instance method. None of the methods in the Math class, such as random, pow, sin, and cos, is dependent on a specific instance. Therefore, these methods are static methods. The main method is static and can be invoked directly from a class. Caution It is a common design error to define an instance method that should have been defined common design error as static. For example, the method factorial(int n) should be defined as static, as shown next, because it is independent of any specific instance. public class Test { public class Test { public int factorial(int n) { public static int factorial(int n) { int result = 1; int result = 1; for (int i = 1; i