A class defines an abstraction using a set of attributes and behavior that represents what is common among objects in a group.. Note To distinguish class variables with variables that ar
Trang 1Most control flow expressions in Java direct program executionbased on a computed true or false value For instance, asyou'll see later in this chapter, an if (expression) statementcauses the next statement to be executed only if expressionevaluates to true. You can actually write something like if (true), but this is not very useful in general (except for
typically evaluate to the true and false literals
associated with the boolean primitive type and not
to an object reference Boolean and boolean are
Table 6.1 Operations on Boolean Expressions
Trang 2= Assignment As in lightOn = true;.
== Equality This produces a true if the two
equivalent to EXCLUSIVE OR (XOR)
operands are true For non-boolean
operands, it is interpreted as a bitwiseoperator
| OR Produces a false if and only if both
operands are false For non-boolean
operands, it is interpreted as a bitwiseoperator
^ XOR Produces true only if exactly one
(EXCLUSIVE OR) operand is true Fornon-boolean operands, it is interpreted
Trang 3The most intuitive comparative operators are those that fall into
a category known as relational operators Relational operatorsinclude the standard greater-than and less-than symbols youlearned about back in third grade Conveniently enough, theywork the same in Java as they did back in third grade, too Forinstance, you know that if you write (3>4), you have writtensomething wrong (a false statement) On the other hand, (3<4)
is correct (a true statement) These examples use literal values,which makes them easy to evaluate, but not very useful in aprogram because their result is known in advance, and it is
always the same Fortunately, in Java and other languages, youare not limited to comparing constants when you use relationaloperators; you are free to use variables, so the statement
(accountBalance > minimumBalance) is also a valid
relational expression that provides much more potential for use
in a flow control statement These expressions are built usingthe operators shown here:
Trang 4non-boolean operands It might not be immediately obvious
what this implies, so consider the following (illegal) expression:
a < b < c
Using left-to-right associativity, the expression a < b is
evaluated first to produce a boolean value of either true or
false. This value would then have to be compared to c. What
does it mean to ask if true (or false) is less than some other
operand? Unlike some languages, a boolean in Java is not the
concatenate boolean values with a string using the + or +=
operator and the string true or false will be displayed in the
output
Listing 6.1 QuickTest.javaA Simple Lesson from the Third
Grade
Trang 6operator (==) is used to distinguish equality comparisons fromassignments In Java then, you would write the expression as(3==3). This would be read as "three equals three" and wouldproduce a true result when evaluated Similarly, the expression(3==4) would evaluate to false.
evaluate the expression However, if the operands are objectreferences, the purpose of these operators is to determine ifboth operands refer to exactly the same object Consider thefollowing example:
string1 == string2
In this expression, string1 and string2 must refer to thesame stringnot to two different strings that happen to containthe same sequence of charactersfor the expression to evaluate
to true. Consider the lines shown in Listing 6.2
Trang 8be compared with another boolean for equality, so a compilererror results here if lastRace is any other data type.
Trang 9is some reason that you must use an expression likethe one just given, be sure to use comments to
explain how the expression operates and, if possible,why you have chosen to implement your algorithmthat way
Trang 10Wrapping the Primitive Types in ClassesUsing the Standard Mathematical Functions
Trang 11Building a UML Class DiagramTroubleshooting
Trang 12Classes are the building blocks of an object-oriented system, soit's important to define them and talk about how they relate toobjects before you learn to declare and use them On one hand,objects are relatively easy to define because they surround you.Obviously, this book you're reading and the keyboard on whichyou type are both objects The concreteness of objects makesthe concept simple to graspobjects are specific things (persons,places, ideas, and so on if you want to be complete) Turning toclasses, however, you must trade this concrete view for the
abstract
In nearly every aspect of life, from simple conversation to
scientific research, people have found it easier to understandobjects and work with them after they have been put into
categories that make similarities and differences clear The
world is too complex otherwise Imagine Henry Ford trying toexplain his plans for the Model T when there was no such
abstraction as a "car" from which to start When an automakerintroduces a new model today, you might be anxious to seewhat it looks like but no one has to tell you what it does Whenabstractions are used to group objects, the key is to focus onwhat they have in common and ignore the ways in which theydiffer when those differences are unimportant in a given
context
So how does this relate to classes? A class defines an
abstraction using a set of attributes and behavior that
represents what is common among objects in a group From aprogramming standpoint, these attributes are variables thatrepresent state and you define methods to act on these
variables as a way to model behavior With proper adherence toencapsulation, these methods define everything that is allowed
in terms of accessing, using, and changing the state of an
object Any behavior that is important to the system you're
Trang 13to state and behavior With this in mind, you decide you need aclass named StopLight. The first step is to define variables tohold the state of a StopLight. As an initial pass, you decidethat the color of the light is the only state of a StopLight thatthe rest of your system needs to know To represent this state,you select a single integer variable named greenYellowRedthat will hold the value of the light color Java offers a muchbetter way than using an integer here but you'll learn aboutthat a little later Given these design choices, here's an exampleclass declaration:
it is likely that you would have a method called
changeLight(), which would cause the light to change fromred to green (probably by changing the greenYellowRed
variable) The following modified declaration of StopLight
Trang 14Note
To distinguish class variables with variables that areparts of methods, class variables are often referred
to as fields, or class scope variables In the previous
example, the greenYellowRed variable would be afield of the StopLight class
Trang 15When dealing with classes, it's important to remember that
classes do not enable programmers to do anything more thanthey would be able to do without them Although it might besignificantly more work, you could write all OOP programs
structurally
Classes are used for the same reason large companies are
divided into departments and those departments are dividedinto subdepartments When a company is faced with organizinghundreds of people around hundreds of tasks, a divide and
conquer strategy is the only way to survive A departmentalarchitecture divides tasks into manageable, and hopefully
related, pieces that can be addressed by an appropriate group
of staff If you're in the engineering department, you care aboutgetting your paycheck on time, but you're probably not
concerned with how the payroll system knows how to handlepaid holidays If you're in the payroll department, however, youmight care a great deal As far as the rest of the company isconcerned, the processing of paychecks has been fully
encapsulated within the payroll department Taking this sameidea and moving it into the software arena is what OOP doeswhen responsibility is divided among classes As with a
company department, each class should be able to do one thingand do it well so the rest of the system can be assured that theassigned tasks are carried out
intricacies of that task and use the class and the methods itprovides Because the class mechanisms are hidden within its
Trang 16Beyond encapsulation, classes allow you to change how youthink about the elements of your programs By writing classesthat enclose everything associated with particular tasks or
entities, you can build types that have meaning in the problemdomains in which you work You are not limited to describingyour program elements as integers, Booleans, or any other
native data type Instead of using these relatively indistinct
mechanisms and relying on unattached functions to interprettheir values appropriately, you can build software with classtypes that help describe the problem being solved In the
preceding payroll example, a procedural approach could be
implemented that maintains holidays as integer day and monthvalues that are compared against the dates in a pay period
whenever a paycheck amount is calculated However, think ofhow much more expressive a class-based approach could be.Using a Calendar class, holidays could be maintained as a
collection of Date objects To produce a paycheck, each dayduring a pay period could also be represented as a Date that isqueried for whether it's a weekend day or holiday relative to thecurrent Calendar. The processing that must be performeddoesn't change significantly between the two approaches, but asystem built on classes allows responsibility to be clearly
divided and produces entities that support the thought processrequired to solve the problem
Although encapsulation frees developers who use a class fromhaving to know the implementation details, it is also a powerfulmeans of preventing accidental corruption of the data Whenaccess to the data members of a class is managed through
methods, relationships between members can be maintained sothat invalid states do not occur
Encapsulation and the capability to create your own descriptive
Trang 17is in its support for inheritance You'll learn more about the
mechanics of inheritance a little later, but for now think of it as
a way to pull common behavior out of multiple classes and
implement that behavior in a separate class so that it can beshared
As an example of inheritance, consider a program that managesthe accounts at a bank Assume the bank offers both checkingand savings accounts to its customers Viewing each type
separately, you could write independent code to support therequired functionality However, this is unnecessary effort and amaintenance headache waiting to happen given the commonfeatures checking and savings accounts share A better
approach is to factor out the common attributes and behaviorshared by the account types and define a class to representthem You can define a class called GeneralAccount for thispurpose with an account balance attribute and methods to
check the balance, make a deposit, and make a withdrawal Youwon't use this GeneralAccount class to represent an actualaccount object but you can use it to simplify the development ofCheckingAccount and SavingsAccount classes If checkingaccounts at this bank do not pay interest, you can inherit thefunctionality of GeneralAccount when declaring
structures in a software system
Note
When new classes inherit the properties of another
Trang 18relate them Code that makes use of a polymorphic type makesmethod calls on a reference to the superclass and the behaviorthat results is determined by the particular subclass
application displays the drawing using a loop that checks eachfigure created by the user and calls a specific function that
knows how to draw that type of shape This approach worksreasonably well until the program users add a requirement that
a triangle must also be supported as a drawing tool A
programmer must then locate the drawing loop, and every
other place shapes are treated differently based on their type,and update the code to understand triangles This update is not
Trang 19maintenance and reliability drawback that can get out of handquickly in a system with any true complexity With OOP,
encapsulation comes into play first as a better approach to thisprogram The functions for drawing different shape types should
be located in the code that defines each shape, namely withinCircleShape, RectangleShape, and TriangleShape
classes The drawing functionality should be implemented as adraw method that holds all the knowledge required to draw theassociated shape on the screen This is already an improvementbecause the behavior of each shape is now encapsulated withinthe definition of the shapes themselves This encapsulation
significantly reduces the number of places code must be
modified if the drawing requirements for a particular shape arelater changed
There's still more, however A drawback in our system so far isthat although the draw methods are encapsulated within
classes, the program still has to call a separate method for eachshape type when the screen needs to be displayed This is
unnecessary effort because the program does not care aboutthe shape types; it only wants them to be drawn correctly Thecapability for a shape to be drawn correctly is a common
behavior found in each of the shape classes (CircleShape, RectangleShape, and TriangleShape)
This is where polymorphism comes into play Instead of definingthree unrelated classes, you can factor out the common
behavior that, in this case, is the capability for a shape to drawitself The example becomes a true OOP implementation when aGenericShape class with a draw method is defined as a
superclass for each of the three shape classes A
GenericShape does not correspond to any real shape, so ithas no implementation for its draw method However, this classdoes serve a significant purpose by declaring that its subclassesmust support a draw method With this change, the programcan keep track of its shapes as GenericShape instances rather
Trang 20than a collection of CircleShape, RectangleShape, andTriangleShape instances This works because the programdoesn't need to know the difference, provided that it can direct
a shape of any type to draw itself When it's time to draw thescreen, the draw method of each GenericShape can be calledand, through polymorphism, the draw method of the specificshape type is called
the CircleShape and RectangleShape classes
can be treated just like the GenericShape class in
Java, you cannot perform an operation such as
getRadius that is reserved for the CircleShape
class on an instance of the GenericShape class
Trang 21As stated at the beginning of this chapter, classes are the
building block in an object-oriented language such as Java Infact, Java, unlike C++, goes so far as to make it impossible todefine any variables or methods outside a class Everything you
do in Java is based on designing and implementing classes
Trang 23public GeneralAccount( String accountNum ) { accountNumber = accountNum;
}
public void makeWithdrawal( float amount ) { balance -= amount;
public class GeneralAccount
Declaring a class states several things, but probably the mostimportant one is the name of the class (GeneralAccount) Inthe case of any public class, the name of the class must alsomatch the name of the file that contains it In other words, thisclass must appear in the file GeneralAccount.java.
Trang 24A bit farther down, you will see several comments As you
learned in "Comments" (Chapter 3, "Data Types and Other
Tokens" ), comments can exist anywhere in the file and are
ignored by the compiler, but they help you leave messages foryourself or other programmers Next, you will see several fieldsdeclared Each of these variables is accessible from any of themethods in the class When you change them in one method, allthe other methods will see the new value
Trang 25In general, Java class declarations take the form
AccessSpecifier Modifiers class NewClass extends SuperclassName implements InterfaceName
Trang 26classes are known as inner classes and are discussed later in
this chapter When declaring a top-level class, you can statethat the class has public access, which is what you have seen
in the examples so far, or you can omit the access specifier andaccept the default access restrictions
Public Classes
Using the public specifier in a class declaration makes the
class accessible to all other classes A public class can be used(for example, as a data type for a class variable or a type for amethod parameter) or extended by any class Here's an
Trang 27programmer Packages provide a way to organize your code byplacing related classes together Access restrictions are lessstringent between classes within the same package because theintent is for these classes to work together as a cohesive unit.With that said, package access can be distinguished from publicaccess Whereas any class can use a public class, by omittingthe public modifier, you can declare a class for use only byclasses within the same package
Remember that although package is a keyword in Java, you donot use it (or any other access specifier) in a declaration for aclass with package access Here's an example declaration:
class PictureFrame
Note
Package access is also known as "default" or
"friendly" access "Default" access is an appropriate
an inheritance hierarchy Note that both modifiers cannot beused in a single class declaration The reason for this will beclear after the supported modifiers are defined
Trang 28inheritance is supposed to be one of the appeals of object-oriented programming
It is important to remember that the object-oriented approacheffectively enables you to create alternate versions of a class(by creating children that inherit its properties and change itsomewhat) Consequently, if you create a class to serve as acomplete implementation of some particular function (for
example, a class that will handle network communications using
Trang 29possibility and ensure consistency The final modifier givesyou a precise way to make your intent clear to other
programmers regarding the use of a class
In addition, the compiler can carry out a number of
performance optimizations on a final class that otherwise wouldnot be possible Polymorphism allows you to write flexible code,but the associated dynamic method calls degrade performancesomewhat If you write code that calls a method on a non-finalclass instance, the compiler must allow for the possibility thatthe instance encountered at runtime will actually be an instance
of a subclass This means that the method must be looked upwhen the code is executed rather than being known when theclass is compiled If, instead, you use a final class, the methodcall is fully defined during compilation because there is no
possibility of a subclass instance being used Of course, thefinal modifier should only be used when a class should have
no subclasses The performance advantage is a side effect only,but you should use this as incentive to consider whether yourclasses should allow subclasses when you are declaring them.Here's an example declaration for a final class:
Trang 30must be extended before an instance can be created The
abstract modifier indicates that a class implementation is
incomplete and must be added to before it can represent anactual object A declaration for an abstract class takes the
following form:
abstract class PictureFrame
A class that you have completely written and compiled can beincomplete depending on how common behavior is isolated andreused in an inheritance hierarchy The superclass that containsthe common behavior in such a hierarchy often does not containenough behavior to represent a valid object For example,
consider a grammar-checking program that must support
multiple written languages You could proceed by defining anEnglishChecker, a FrenchChecker, and a
SpanishChecker class in which each defines the required
functionality for a given language Knowing that some of themethods you need are independent of the language, you define
a GrammarChecker class as a common superclass that
contains these methods rather than repeating them in each
class This alone does not produce an abstract class, becauseeven though GrammarChecker does not implement all you
checkPunctuation(), this method can be declared in
GrammarChecker without an implementation (that is, an
Trang 31flexible design needed for this example This structure supports
independent functionality of the program If a programmer laterneeded to add a GermanChecker class, a perfect starting pointwould be to look at the list of abstract methods in
a clean separation of the language-dependent and language-GrammarChecker to gain an understanding of what behaviorhas to be provided to support a new language
Begin with a letter, an underscore (_), or a currency symbol($, £, and so on)
Contain only letters, digits, underscores, and currency
Trang 32Not be the same as any Java keyword (such as void orint)
Also, it is accepted practice to capitalize the first letter in thename of a class and use mixed case instead of underscores toseparate words (for example, MyClassName)
Although only required for public classes, it is generally a goodpractice to name the file in which NewClass is defined
NewClass.java. Doing so helps the compiler find NewClass,even if NewClass has not been compiled yet
SuperclassesExtending Another Class
One of the most important aspects of OOP is the capability touse the methods and fields of a class you have already built.This can be done by declaring a member variable that is a
Trang 33By extending a class, you gain all the functionality of a
superclass while providing yourself the opportunity to add newbehavior or even modify existing behavior If you declare asubclass without defining any fields or methods (and use thesame access specifier and modifier, if any), the new class willbehave identically to its superclass and only differ by its name.The subclass would not be very interesting but it would be avalid class, and it would have all the fields and methods
Trang 34A common mistake in object-oriented programming is to overuse inheritance Although inheritance is a powerful feature, a class hierarchy can become rigid if inheritance is taken to the extreme A standard rule of thumb is to apply the "is- a" versus "has-a" test.
For example, a Ford is a car, so a class hierarchy that defines a Ford class as a subclass of a Car class makes sense This example strictly follows an "is-a" definition, because there is nothing that a Ford does that a generic Car does not do A Ford is a unique classification of Car that has its own implementation
of automotive behavior, but you don't need to add some new capability, such as floating on water, when you declare a Ford class.
Slightly different from an "is-a" justification for inheritance is the "is-like-a" test.
In this case, you make use of inheritance to declare a subclass that is similar enough to its superclass to share its interface, but it is also dissimilar in that it requires additional methods to represent its behavior completely This design is not as clean an approach because treating the subclass as its superclass doesn't allow you to exercise all its functionality, but it can be useful.
If two classes cannot be described as having an "is-a" or "is-like-a" relationship,
you should not inherit one from the other For example, a car has an engine, but
it isn't an engine, so Car should not be a subclass of an Engine class A
composition approach should be used here so that Car contains a reference to
an Engine and delegates all functionality related to powering the vehicle to that instance.
The appropriate use of inheritance in these simple examples is obvious, but this
is not always the case You should exercise caution when considering inheritance and more often stress composition and delegation in your class designs to make them more flexible and better able to adapt to new requirements during their lifecycles.
Trang 35Obviously, variables are an integral part of programs and, thus,classes as well In Chapter 3, you examined the various types
of variables, but now you must also consider how they are
employed in your programs and the different roles they canassume
When creating variables, whether they are as simple as integers
or as complex as derived classes, you must consider how theywill be used, what code will require access to the variables, andwhat degree of protection you want to provide to these
variables
The capability to access a given variable is dependent on twothings: the access specifier used when creating the variable andthe location of the variable declaration within a class
See "Literals: Assigning Values,"
Trang 36encapsulate your code into self- sufficient and more logical
chunks
Furthermore, because OOP encourages and facilitates the reuse
of code that you have written beforehand, careful assignment ofaccess restrictions to code you write now prevents you fromlater doing something that you shouldn't
(Keep in mind that preventing access to a field does not preventthe use of it.) For example, if you were creating a Circle
class, there would most likely be several fields that would keeptrack of the properties of the class, such as radius, area, bordercolor, and so onmany of which might be dependent on each
other Although it might seem logical to make the radius fieldpublic (accessible by all other classes), consider what wouldhappen if a few weeks later you decided to write the code
Trang 38statement would change the radius, it would not affect the areafield (remember that the area of a circle is a function of theradius and is equal to times the radius squared) As a result,you would be supplying the paintBall() method with
incorrect information
Because the area field depends on the radius, it should beupdated whenever the radius is changed Your first thoughtmight be to ask why area is a field at all instead of just beingthe return value of an area() method that is computed based
on the radius when needed Using a field that is derived fromone or more other fields is a common approach when
addressing performance Assume, in this case, that
performance is critical when the area of the circle is needed.Calling a method that computes the area each time is extraoverhead if the radius has not changed since the last call
Declaring a field to hold the area offers a better solution whenthe radius and area fields are properly protected as shown in
Trang 39from outside the class, the area field is updated accordingly
This way the area of the circle is always correctly represented
by the field and is never computed unnecessarily