When that happens here, the result on the screen is this: We can add a new class called SportsCar that will inherit from Automobile, and we can give theSportsCarclass a different acceler
Trang 1Finally, the three println statements at the end print a text representation of each Automobile Suchuse of an object’s name, such as economy, inside println causes the JVM to use the toString() method
of the class When that happens here, the result on the screen is this:
We can add a new class called SportsCar that will inherit from Automobile, and we can give theSportsCarclass a different accelerate() method Here is the Java class for SportsCar:
/**
* Class SportsCar
* Inherits from class Automobile
* @author Carl Reynolds
*/
class SportsCar extends Automobile {
private double maxSpeed = 150.;
//override of inherited accelerate() method
public void accelerate( double newSpeed )
{
if( newSpeed > maxSpeed ) speed = maxSpeed;
else speed = newSpeed;
}
}
The SportsCar class extends the class Automobile; that means SportsCar inherits fromAutomobile Any instance of a SportsCar will also be an Automobile, and except where there are differences between the code for SportsCar and the code for Automobile, an instance of a SportsCarwill have exactly the same state variables and behavior as any instance of the class Automobile
The SportsCar class must also have a constructor; it’s called SportsCar The constructor forSportsCarsimply uses the constructor for Automobile, the superclass, by using the super key word topass the same values for make, model, year, and power to the constructor for the Automobile class
The only difference between instances of SportsCar and instances of Automobile will be the behavior provided by the accelerate() method In the case of an Automobile, the maximum speed will
be 70, but in the case of a SportsCar, the maximum speed will be 150 We say that the subclass SportsCar
overrides the accelerate() method inherited from the superclass Automobile.
Everything else that is true about an Automobile object will be true about a SportsCar object.All will have instance variables to store make, model, year, horsepower and speed Creating either a new
Trang 2Automobile or a new SportsCar will increment the count of Automobiles maintained by theAutomobileclass.
We didn’t have to change any of our existing code to enhance our work to treat sports cars differently fromother automobiles!
POLYMORPHISM
The word polymorphism means “many forms.” When a subclass overrides a method of a superior class, thebehavior of the method will depend upon which type of object is being used in the program, an instance of thesuperior class or an instance of the subclass This characteristic of OO programming is called polymorphism,and it is a powerful feature of the OO approach
We will add some lines to our AutomobileFactory class to set the speed of a family car to 120 andset the speed of a sports car to 120 Looking back at the accelerate() method for the class Automobile,you will see that the maximum speed for an instance of the Automobile class is 70 Compare that with the accelerate()method for the SportsCar class; the top speed for a SportsCar is 150
When we call the same accelerate() method for an instance of Automobile and an instance ofSportsCar, the results are different The Automobile speeds up to 70, and the SportsCar speeds up to
120 To show this, add code to the AutomobileFactory class:
//polymorphism will cause the effects to be different
System.out.println( family + " " + family.getSpeed() );
System.out.println( sports + " " + sports.getSpeed() );
Polymorphism allows us to write programs in a more general way We can reference the superior class as
we write programs, and if the object being used by the program happens to belong to a subclass of the superior
Trang 3class, the methods in the subclass which override the corresponding methods in the superior class will insure thatmethods appropriate to the particular instance will be called This is another way in which OO programmingreduces the amount of code that must be written and tested, and also promotes reuse of existing code in newapplications.
INTERFACES
In Java, we can also specify an interface to enforce a common set of behaviors among different classes.
For example, think about the problem of sorting a group of Automobile objects How should Automobiles
be ordered? By year? Alphabetically by make? By horsepower? This problem arises frequently when we’reworking with objects, so the Java language specifies an interface that any new class can implement in order
to facilitate sorting instances of the new class
An interface consists of one or more method signatures, but it does not contain any code implementing any
of the methods (An interface can include constants as well as method signatures, but we will focus on the ods.) A method signature is like the first line of a method; the signature specifies what the method will return,the name of the method, and what arguments the method expects when it is called
meth-For example, Java provides the interface Comparable, and the Comparable interface specifies a singlemethod called compareTo() The compareTo() method expects an object as an argument (the object withwhich to compare the first instance) and it returns an int The value of the returned int will be 0 if the twoobjects being compared are equal, -1 if the first object is “smaller” (should be ordered first), and +1 if the firstobject is “larger” (should be ordered second)
We can implement the interface Comparable in our Automobile class by adding this code to our classAutomobile:
class Automobile implements Comparable<Automobile> {
The new compareTo() method implements the Comparable interface for the class Automobile.We’ve taken a shortcut here which takes advantage of the toString() method we already have forAutomobile The phrase this.toString() will return a String object which represents this instance
of an Automobile The key word this always references the particular instance itself The Stringreturned will be of this form:
Trang 4toString() representation of Automobiles sorted in ASCIIbetical order would be fine Older cars will be ordered first, and among cars of the same year, cars will be sorted ASCIIbetically by make andmodel.
The interface idea is similar to the idea of a class, in that an interface creates a new data type When the class Automobile implements the interface Comparable, instances of Automobile can also betreated as instances of Comparable Just as good design of a class hierarchy can reduce programming andimprove reliability, good interface design can also
For instance, the sort() method of the Java Collections class will sort lists of Comparableobjects Our Automobile class implements Comparable, Java’s String class implements Comparable,Java’s Date class implements Comparable, etc One sort() method will work for any group of objectswhose class implements Comparable That alone is a great example of code reuse
It’s easy to design and use your own interfaces, too However, in this brief chapter we will not be discussingthat topic
ERROR HANDLING
Java uses Exceptions to represent error conditions
Exceptionis actually a class in Java, and when a program creates an Exception, it creates a newobject, which is an instance of the Exception class An Exception object can have information about whatwent wrong, usually including an error message, and a “stack trace” showing which method created the error.Having created an Exception object when something goes wrong, the program “throws” the Exceptionusing the key word throw The JVM will print an error message and stop execution when a program throws
an Exception, unless the programmer has provided code to “catch” the exception and handle the error condition in the program This approach to handling program errors is called “exception handling” for obviousreasons, and it’s a relatively modern idea
One advantage of handling errors this way is that code to handle error conditions will be segregated intocode blocks separate from the main logic of the program This makes it much easier to follow the intent of theprogrammer, both in the main logic and in the error handling code
Java provides many subclasses of Exception so that different problems result in different classes
of Exception objects being thrown Some examples include FileNotFoundException,NullPointerException, and NumberFormatException
Java recognizes two types of Exceptions, checked and unchecked The names come from what the Javacompiler does with them The compiler “checks for” appropriate handling of checked Exceptions, but doesnot check for handling of unchecked Exceptions
An unchecked Exception represents an error that is probably too serious for an application to correct
An example is the NullPointerException, which occurs when the program tries to access a variablewhich should contain a reference to an object, but which contains null instead The compiler assumes that such
an exception should cause the program to terminate with an error condition, so it does not check to see that theprogram has code to handle that error condition itself
A checked exception such as FileNotFoundException represents an error condition from which the program potentially could recover In the case of FileNotFoundException, for example, the program could prompt the operator for a new file name and try again If the compiler recognizes that a method could encounter a checked exception, the compiler will require that the method either provide a handler for that exception or declare with its own throws declaration that it can itself generate the checkedException
The way to add exception handling to a Java program is to enclose program statements which might
gen-erate an Exception within a try block A try block begins with the key word try and an open curly brace.
At the end of the code being included in the try block is a close curly brace Immediately following the try block
will be one or more catch blocks A catch block contains the code to handle the error.
Let’s go back to our Automobile class and its accelerate() method Instead of simply setting thespeed of the Automobile to its maximum value when the argument to the accelerate() method is toolarge, we can have the Automobile class generate a special subclass of Exception appropriate to thisapplication Here is the code for our new ExcessiveSpeedException class:
Trang 5public class ExcessiveSpeedException extends Exception {
Now we can rewrite the accelerate() method of Automobile as follows:
public void accelerate ( double newSpeed )
throws ExcessiveSpeedException {if( newSpeed > 70 )
throw new ExcessiveSpeedException( this );
speed = newSpeed;
}
The reference to this means that the particular instance of Automobile that generates theExcessiveSpeedExceptionwill be passed to the ExcessiveSpeedException constructor Noticethat the method header for accelerate() now includes a declaration that the method can throw anExcessiveSpeedException If you forget to include the declaration, the compiler will require such a declaration when it sees that some statement within the method throws an ExcessiveSpeedException.Finally, notice that we no longer require an else clause after the if statement Once a method throws anexception, execution stops, except for whatever code is ready to catch the Exception Therefore, we nolonger need else to insure two non-overlapping paths of execution in response to the test in the if statement
We can rewrite the AutomobileFactory class to handle the possible occurrence of anExcessiveSpeedException
System.out.println( family + " " + family.getSpeed() );
System.out.println( sports + " " + sports.getSpeed() );
}
In this case, the catch block simply reports the error, and the program continues on With other errors, thecatch block might try to correct the problem, ask the user for a decision, or simply terminate the program bycalling System.exit()
The output from this version of AutomobileFactory looks like this:
Trang 6When AutomobileFactory tries to accelerate the VW to too great a speed, the Automobile classthrows an ExcessiveSpeedException which stops execution of accelerate() and transfers control
to the catch block The catch block reports the problem by printing the message attribute of the Exceptionobject When the catch block completes, the program continues, but the speeds of both Automobiles remain0.0, because the path of execution never set the speed of either one
There can be more than one catch block; in fact, you can have several Each one can specify a particularclass of Exception to handle That is important to segregating code for handling different kinds of problems
If a method throws a FileNotFoundException, it may be easy to fix by asking the operator to enter thefile name again On the other hand, if a read of the file fails and the method throws an IOException, it may
be difficult for the program to recover In the first case the catch block may “soldier on,” and in the second casethe catch block may simply report the error and then call System.exit()
When more than one catch block follows a try block, the catch blocks should be ordered such that level Exception classes occur before higher-level, more general classes of Exceptions When a methodthrows an exception, the try block searches down the list of catch blocks until it finds a match between theExceptionclass that was thrown and the Exception class declared in the catch block The first acceptablematch will be invoked to handle the error If the first catch block specifies objects of class Exception, themost general class, the first catch block will handle all Exceptions, regardless of whatever other catch blocks there may be So, if a program wants to attempt to recover from a FileNotFoundException andterminate on any other failure, the catch block for the FileNotFoundException should come before thecatch block for the class Exception
lower-There’s one more option After the try block and all the catch blocks, a programmer can add a finally block.
A finally block contains code that will always be executed, whether an error occurs or not A finally block is
a good place to put general “clean-up” code, like the statement to close a data base
Here is the syntax for the try/catch/finally construction:
//If code is successful, or exception is caught and
// handled, execution will continue here
Trang 7Java’s error-handling mechanism is one of its great strengths Exception handling with try/catch/finallyis very robust and leads to very supportable code Since one can easily add application-spe-cific exception classes to support one’s own work, this approach is also very extendable.
INPUT AND OUTPUT
Java programs read and write data by means of streams A stream is a series of data elements that flows
from some input device to the program, or from the program to some output device The general approach toinput and output (I/O) from a Java program is to:
Open the stream
While there is data to read or write
read and process data, or write data
}
Close the stream
The stream classes for I/O are grouped together in a Java package called java.io A package is just a
collection of related classes One can create packages of one’s own classes, but we will not be describing that
in this brief introduction to the language The reason to mention the package name here is that a programmermust import a package in order to take advantage of the classes within it In order to use the stream classes
we will soon discuss, your program must have a statement at the very beginning, even before the class statement, that says,
import java.io.*;
The asterisk means to import all the classes in the package If the programmer wants only one of theclasses, the programmer can substitute the class name for the asterisk Usually one simply types the line as wehave shown it
The stream classes in Java are divided into two great categories: Reader/Writer and InputStream/OutputStream If the class is in the Reader/Writer category, it is a stream for reading and writing char-acter data—letters, numbers, and symbols If the class is in the InputStream/OutputStream category, it
is a stream for reading and writing bytes—raw data, 8 bits at a time
Students are sometimes confused thinking about the difference between character data and bytes Are notbytes used to encode characters? Yes they are In fact, we could get along with just the InputStream/OutputStreamclasses, and let programs be responsible for making sense of the data by converting the data tocharacters when that was appropriate
However, often data sources consist of character data, and it is very convenient to have I/O classes for that common situation If the information exists in the form of characters, a Reader/Writer will interpretthe information correctly and return a set of characters to the program This saves the programmer having towrite a tedious conversion that would otherwise be necessary frequently
If the information exists in some other form than characters, such as binary numbers in integer or point format, as in an image file, then it will not make sense to interpret the bit patterns as characters In thatcase, the programmer should use the InputStream/OutputStream classes, which will simply transfer thebytes Then the program will be responsible for interpreting the bytes correctly
floating-One other situation calls for the use of InputStream/OutputStream classes, too That is when onedoes not care what the data represent This would be the case, for example, when the task is to copy a file Theprogram doing the copying does not need to know what the content of the file means; it just needs to copy each byte to a new file In that case, using the InputStream/OutputStream classes instead of theReader/Writer classes makes sense, even if the file to be copied consists of characters, because theInputStream/OutputStreamclasses will be more efficient—the step of translating bit patterns to char-acters will be skipped
Trang 8There are 50 classes in java.io, and we will describe only a few here To read a file of character data,one would use a BufferedReader “wrapped around” a FileReader The Java I/O design is very flexible,and this is a good example of that A FileReader reads characters from a file, and by wrapping theFileReaderwith a BufferedReader, the I/O will be accomplished more efficiently by reading a group
of characters at once The BufferedReader also provides a method called readLine(), which allows theprogram to read a whole line at a time from a file into a String variable Without the BufferedReader, aFileReaderonly has methods to read characters
Here is a little program to read a file of character data and display it on the screen:
import java.io.*;
/**
* A program that opens a character based file,
* specified on the command line,
* and shows its contents on standard output
*
* @author Carl Reynolds
*/
public class ShowFile {
public static void main( String args[] ) {
Trang 9This program checks the command line arguments in the array of Strings called args to make sure that theuser provided a parameter for the file name If the user provided exactly one argument, the program assumes thisargument is the name of a file, and it attempts to open the file using a BufferedReader inside a try block.
If all goes well, the program enters a while loop calling the readLine() method of theBufferedReaderto read a line of the file at a time into the String variable line, and then display thetext using the println() method The loop will terminate when readLine() returns a null value; that is
the signal that the BufferedReader has encountered the end-of-file (EOF).
The program uses the finally block to close the file Since the close() method can itself throw an IOException, the call to close() within the finally block must also be surrounded by
a try block If an error occurs here, however, this program simply ignores it; the catch block is empty
of any code
Our second example reads a file for the simple purpose of copying the bits in the file to a new file For thispurpose we use a BufferedInputStream wrapped around a FileInputStream The program copiesthe bits literally, one byte at a time This approach is highly efficient because there is no overhead of translat-ing the bit patterns into characters
import java.io.*;
/**
* Copy files from the command line
* @author Paul Tymann
* @author Carl Reynolds
*/
public class FileCopy {
public static void main( String args[] ) {
new FileInputStream( args[0]) );
// Open the output file
// If the output file exists, it will be overwritten
out = new BufferedOutputStream(
new FileOutputStream( args[1] ) );
Trang 10an existing file, but we have not used that here.
With the read() method of the BufferedInputStream, either a byte of data is returned, or, if theprogram encounters the EOF, a binary -1 is returned As long as the read() continues to return bytes, theprogram calls write() to copy the data Though you see individual bytes being read and written, the transfer
is much more efficient than you might think, because the InputStream and OutputStream are buffered
SCANNER
Often we need to read information from the user of the program We might prompt the user, for example,
to ask them what kind of car they drive We can ask the question of the user by displaying the question usingSystem.out.println() We have shown many examples of displaying information on the screen.Java provides a class called Scanner that makes it easy to read information from the keyboard into theprogram To create a scanner object for reading from the keyboard, we simply pass the standard input “stream”
to the constructor for a new Scanner For example, here is a snippet of code to create a new Scanner forreading from the keyboard, and then to use the Scanner to read a floating-point number:
You can also use a Scanner to read from a file To associate a Scanner with a file of text, just pass
a FileReader object to the Scanner constructor:
sc = new Scanner(new FileReader( myFile.txt ) );
To read lines of text, you can use the nextLine() method of Scanner to transfer a line of text into a String variable You can also use the hasNextLine() method to test to see whether there is something to read Here’s a snippet of code to loop, reading text for processing into a String calledlineOfData
Trang 11A PrintWriter can be used with any output stream, but a very common use is to make it very easy towrite formatted text to a file Here is a simple program that reads lines of text typed at the keyboard, and writesthe same text into a file using a PrintWriter Using the println() method, this program adds a linenumber at the front of each line as it writes the line to the file.
import java.io.*; //PrintWriter is here
import java.util.*; //Scanner is here
public class PrintToFile{
public static void main( String[] args) {
System.out.print("Enter file name: " );
fileName = sc.nextLine();
myWriter = new PrintWriter( fileName );
System.out.println( "Now enter lines of text." );
System.out.println( "When you are done, " +
"type only Cntrl/z (EOF) on the line." );