Lecture 8 - It works!

advertisement
Chapter 8
Objects & Classes
Definition of Object-Oriented Programming (OOP)
Object-Oriented Programming (OOP) uses the analogy of real objects as a template for creating
computer programs involving those objects.
For example, we all know what a circle is. A circle can be defined by its radius and the location
of its center. A circle has an area that is strictly a function of its radius.
We can create a class that defines a circle. For now we will not concern ourselves with position.
class Circle
{
double radius;
this is a property or attribute
of the Circle class
Circle(double rad)
{
radius = rad;
}
double getArea()
{
return radius*radius*Math.PI;
}
this is called a constructor of
the Circle class. It has the same
name as the class and it must
define all properties of the class
this is an action or method of
the Circle class
}
It is important to note that a class is not a program. There is no main method. A class is used by
an executable program.
Constructors
Constructors are a special kind of method that initialize objects. Constructors have
the following characteristics:
A constructor must have the same name as its class.
Constructors do not have a return type, or void.
Constructors are invoked using the new operator.
class Circle
{
double radius;
Circle(double rad)
{
radius = rad;
}
double getArea()
{
return radius*radius*Math.PI;
}
}
Reference Variables and Reference Types
Circle myCircle;
myCircle = new Circle();
Circle myCircle = new Circle();
A class is similar to a user-defined
type
myCircle is declared as a Circle
type. At this point myCircle is a
reference to objects of type Circle.
We can also create an instance of
the Circle class by using new.
Accessing an Object’s Data and Methods
After an object is created, its data can be accessed and its methods invoked using
the dot operator (.), also known as the object member access operator.
myCircle.radius
returns the radius of myCircle as a double
myCircle.getArea()
computes and returns the area of myCircle
Pointing to Nowhere (null)
public class objtest1
{
public static void main(String[] args)
{
Weasel myWeasel = null;
aWeasel = new Weasel(1,2,10.4);
if(myWeasel == null)
System.out.println("Yes");
else
System.out.println("No");
}
myWeasel
Weasel
null
myWeasel = null;
aWeasel
}
class Weasel
{
int color;
int age;
double weight;
}
Weasel(int col, int a, double w)
{
color = col;
age = a;
weight = w;
}
Weasel
Weasel
color: int = 1
age: int = 2
weight: double = 10.4
myWeasel = new Weasel(1,2,10.4);
Reference Types can Point to Null
class test
{
public static void main(String[] args)
{
Student a_student = new Student();
System.out.println("name = " + a_student.name);
System.out.println("age = " + a_student.age);
System.out.println("gender = " + a_student.gender);
}
}
class Student
{
String name;
int age;
boolean isScienceMajor;
char gender;
}
name = null
age = 0
gender = 00
Unified Modeling Language (UML) Diagrams
The illustration of class templates and objects in Figure 8.2 can be standardized using UML
(Unified Modeling Language) notations. This notation is called a UML class diagram, or simply a
class diagram.
In the class diagram, the data field is denoted as
The constructor is denoted as
The method is denoted as
dataFieldName: dataFieldType
ClassName(parameterName: parameterType)
methodName(parameterName: parameterType): returnType
Instance vs Static Classes
We have used several of the methods provided in the Math class in our programs. These
methods are invoked by calling the class name followed by the method using dot notation. For
example:
Y = Math.sqrt(X);
rnd = Math.random();
maxval = Math.max(Math.max(a,b),Math.max(c,d));
More recently we have been creating instances of classes and then accessing the attributes and
methods of the object class using the same dot notation. For example:
Circle circ = new Circle(10.0);
System.out.println("A circle of radius " + circ.radius +
" has an area = " + circ.getArea());
It is important to note that in the first case we cannot create an instance of the Math class and in
the second we access the methods and attributes only through an instance of the class.
The methods in the Math class are referred to as static methods while those in an instance class
are called instance methods.
Static vs Instance Revealed
public class StaticInstanceDemo
{
public static void main(String[] args)
{
Thing thing1 = new Thing(1);
Thing thing2 = new Thing(2);
System.out.println("thing1.x
System.out.println("thing2.x
System.out.println("thing1.y
System.out.println("thing2.y
class Thing
{
public static int x = 0;
int y;
=
=
=
=
"
"
"
"
+
+
+
+
thing1.x);
thing2.x);
thing1.y);
thing2.y);
=
=
=
=
"
"
"
"
+
+
+
+
thing1.x);
thing2.x);
thing1.y);
thing2.y);
Thing(int a)
{
y = a;
}
public void changey(int newy)
{
y = newy;
}
thing1.changex(42);
thing1.changey(99);
System.out.println("thing1.x
System.out.println("thing2.x
System.out.println("thing1.y
System.out.println("thing2.y
public void changex(int newx)
{
x = newx;
}
}
int getx()
{
return x;
}
}
thing1.x = 0
thing2.x = 0
thing1.y = 1
thing2.y = 2
thing1.x = 42
1 thing2.x = 42
thing1.y = 99
thing2.y = 2
int gety()
{
return y;
}
}
An Example: The Card Deck
Problem: Build a model of a deck of playing cards that can be used in a Java program.
We can define a card object in an instance class as part of a model for a deck of cards. While
many of the details of the Card class will depend on what we want to do with the card deck,
there are a few important attributes common to most card-playing applications.
suit - Hearts, Clubs, Diamonds, Spades
rank - Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King
value - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
public class Card
{
String suit;
String rank;
int value;
Card constructor
Card(String s, String r, int v)
{
suit = s;
rank = r;
value = v;
}
}
Generating the Cards
To create instances of the 52 cards in a deck of playing cards using the Card class,
we need to specify the suit and the rank of each card. We could do this by simply
writing 52 declarations, each one explicitly giving the string names for suit and rank.
Card
Card
:
Card
Card
card_1 = new Card("Heart","Ace",1);
card_2 = new Card("Heart","2",2);
card_51 = new Card("Spade","Queen",10);
card_52 = new Card("Spade","King",10);
This would be a lot of work and we would have 52 variables that would be difficult
to use in a program. Alternatively we could generate an indexed list of Card type
objects.
Card[] card = new Card[52];
This creates a list of 52 references to Card types but it doesn't create instances of
cards. We will still have to declare each of them separately. However, this time we
can use a for-loop to save ourselves a lot of typing.
A Bit of Computer Science
In order to avoid generating 52 separate declarations, we need a way to specify the
suit and rank of each card in a for-loop. The loop index will range from 0 to 51. We
can use this value to generate a suit number (0-3) and a rank number (1-13).
We can generate all the cards of the same suit first or all cards of the same rank first.
In each case we can use integer division and modulo to convert the loop index into a
suit number and a rank number.
int suitnum, ranknum;
int suitnum, ranknum;
for(int i = 0; i<52; i++)
{
suitnum = i/13;
ranknum = i%13 + 1;
}
for(int i = 0; i<52; i++)
{
ranknum = i/4 + 1;
suitnum = i%4;
}
i suitnum ranknum
0
0
1
1
0
2
2
0
3
:
50
3
12
51
3
13
i suitnum ranknum
0
0
1
1
1
1
2
2
1
:
50
2
13
51
3
13
Converting Numbers to Strings
The constructor for the Card class needs strings for the name of the suit and the rank.
We can use conditional statements that choose the strings based on the values of the
suit number and the rank number.
switch (suitnum)
{
case 0:
suit = "Club";
break;
case 1:
suit = "Spade";
break;
case 2:
suit = "Heart";
break;
case 3:
suit = "Diamond";
break;
}
if(ranknum==1)
rank = "Ace";
if(ranknum>1 & ranknum<10)
rank = Character.toString((char)(ranknum + 48));
if(ranknum == 10)
rank = "10";
if(ranknum == 11)
rank = "Jack";
if(ranknum == 12)
rank = "Queen";
if(ranknum == 13)
rank = "King";
value = 10;
if(ranknum<=9)
value = ranknum;
deck[i] = new Card(suit,rank,value);
if(ranknum==1)
rank = "Ace";
if(ranknum>1 & ranknum<10)
rank = Character.toString((char)(ranknum + 48));
if(ranknum == 10)
rank = "10";
if(ranknum == 11)
rank = "Jack";
if(ranknum == 12)
rank = "Queen";
if(ranknum == 13)
rank = "King";
public class Deck
{
String suit = "";
String rank = "";
int suitnum, ranknum, value;
Card[] card = new Card[52];
int topcard;
Deck()
{
topcard = 0;
for(int i = 0;i<card.length;i++)
{
suitnum = i%4;
ranknum = i/4 + 1;
card[i] = new Card(suit,rank,value);
}
}
public void shuffle()
{
Card tmpcard;
topcard = 0;
for(int i=0;i<1000;i++)
{
int k,m;
k = (int)(Math.random()*52.0);
m = (int)(Math.random()*52.0);
tmpcard = card[k];
card[k] = card[m];
card[m] = tmpcard;
}
}
value = 10;
if(ranknum<=9)
value = ranknum;
switch (suitnum)
{
case 0:
suit = "Club";
break;
case 1:
suit = "Spade";
break;
case 2:
suit = "Heart";
break;
case 3:
suit = "Diamond";
break;
}
public Card dealCard()
{
Card the_card;
the_card = card[topcard];
if(topcard<51)
topcard += 1;
return the_card;
}
}
Data Encapsulation
public class Circle3
{
private double radius = 1;
private static int numberOfObjects = 0;
public Circle3()
{
numberOfObjects++;
}
public Circle3(double newRadius)
{
radius = newRadius;
numberOfObjects++;
}
public double getRadius(double newRadius)
{
return radius;
}
public void setRadius(double newRadius)
{
if(radius>=0)
radius = newRadius;
else
radius = 0.0;
}
public static int getNumberOfObjects()
{
return numberOfObjects;
}
public double getArea()
{
return radius * radius * Math.PI;
}
}
We have written several programs using
classes, most of which leave the data value
types as public.
There are times which we do not want to allow
direct access to the data values inside a class.
In these cases we can simply declare them a
private.
If we wish to permit limited access to them we
can include accessors in the class.
If we wish to allow the user of the class to see
the value we create a get accessor. If we also
want to allow the class user to change the
value we create a set accessor.
Testing the Circle3 Class
public class TestCircle3
{
public static void main(String[] args)
{
Circle3 Circ = new Circle3(5.0);
System.out.println("The area of the circle of radius " + Circ.getRadius() + " is " + Circ.getArea());
Circ.setRadius(myCircle.getRadius() * 1.1);
System.out.println("The area of the circle of radius " + Circ.getRadius() + " is " + Circ.getArea());
System.out.println("The number of objects created is " + Circle3.getNumberOfObjects());
}
}
The data field radius is declared private. Private data can be accessed only within their defining
class. You cannot use Circ.radius in the client program. A compile error would occur if you
attempted to access private data from a client.
Since numberOfObjects is private, it cannot be modified. This prevents tampering. For example,
the user cannot set numberOfObjects to 100. The only way to make it 100 is to create 100 objects
of the Circle3 class.
Array of Objects
Sometimes it is convenient to create an array of objects. The declaration of the array creates an
array of reference types but does not instantiate any of the objects. This is done in a separate
statement calling the class constructor.
public class Deck
{
String suit = "";
String rank = "";
int suitnum, ranknum, value;
Card[] card = new Card[52];
int topcard;
:
:
Deck()
{
topcard = 0;
for(int i = 0;i<card.length;i++)
{
suitnum = i%4;
ranknum = i/4 + 1;
:
:
card[i] = new Card(suit,rank,value);
}
Declaration of an array of objects
Initialization of the array of objects
Download