3.0 Java Programming Tutorial OOP Exercises 3.4 Understanding Objects PDF
3.0 Java Programming Tutorial OOP Exercises 3.4 Understanding Objects PDF
OOP Exercises
TABLE OF CONTENTS
1. Exercises on Classes and Instances
1.1 Exercise: The Circle Class
1.2 Exercise: The Author and Book Classes
1.3 Exercise: The MyPoint Class
1.4 Exercise: The MyCircle Class
1.5 Exercise: The MyTriangle Class
1.6 Exercise: The MyComplex class
1.7 Exercise: The MyPolynomial Class
1.8 Exercise: Using JDK's BigInteger Class
1.9 Exercise: The MyTime Class
1.10 Exercise: The MyDate Class
1.11 Exercise: Book and Author Classes Again - An Array of Objects as an Instance
Variable
1.12 Exercise: Book and Author Classes Once More - A Fixed-length Array of Objects
as an Instance Variable
1.13 Exercise: Bouncing Balls - Ball and Container Classes
1.14 Exercise: Ball and Player
2. Exercises on Inheritance
2.1 Exercise: The Circle and Cylinder Classes
2.2 Exercise: Superclass Shape and its subclasses Circle, Rectangle and Square
3. Exercises on Composition vs Inheritance
3.1 Exercise: The Point and Line Classes
3.2 Exercise: Circle and Cylinder using Composition
4. Exercises on Polymorphism, Abstract Classes and Interfaces
4.1 Exercise: Abstract Superclass Shape and Its Concrete Subclasses
4.2 Exercise: Polymorphism
4.3 Exercise: Interface Movable and its implementations MovablePoint and
MovableCircle
4.4 Exercise: Interfaces GeometricObject and Resizable
5. More Exercises on OOP
5.1 Exercise: The Discount System
5.2 Exercise: Polyline of Points with ArrayList
6. Exercises on Data Structure and Algorithm
6.1 Exercise: MyIntStack
1. Exercises on Classes and Instances
1.1 Exercise: The Circle Class
A class called circle is designed as shown in the following class diagram. It contains:
Two private instance variables: radius (of type double) and color (of type String),
with default value of 1.0 and "red", respectively.
Two overloaded constructors;
Two public methods: getRadius() and getArea().
The source codes for Circle is as follows:
public Circle() {
radius = 1.0;
color = "red";
public Circle(double r) {
radius = r;
color = "red";
return radius;
return radius*radius*Math.PI;
Compile "Circle.java". Can you run the Circle class? Why? This Circle class does not
have a main() method. Hence, it cannot be run directly. This Circle class is a “building
block” and is meant to be used in another program.
Let us write a test program called TestCircle which uses the Circle class, as follows:
2. // Construtor to construct a new instance of Circle with the given radius and color
Modify the test program TestCircle to construct an instance of Circle using this
constructor.
3. Getter: Add a getter for variable color for retrieving the color of a Circle instance.
9. radius = r;
10. }
11.
13. Keyword "this": Instead of using variable names such as r (for radius) and c
(for color) in the methods' arguments, it is better to use variable names radius
(for radius) and color (for color) and use the special keyword "this" to resolve the
conflict between instance variables and methods' arguments. For example,
16.
Modify ALL the constructors and setters in the Circle class to use the keyword
"this".
21. Method toString(): Every well-designed Java class should contain a public
method called toString() that returns a short description of the instance (in a
return type of String). The toString() method can be called explicitly (via
instanceName.toString()) just like any other method; or implicitly through
println(). If an instance is passed to the println(anInstance) method, the toString()
method of that instance will be invoked implicitly. For example, include the
following toString() methods to the Circle class:
22. public String toString() {
Try calling toString() method explicitly, just like any other method:
Circle c1 = new Circle(5.0);
anAuthor.setEmail("paul@nowhere.com")
System.out.println(anAuthor);
Book anotherBook = new Book("more Java for dummy", new Author(......), 29.95, 888);
Take note that both Book and Author classes have a variable called name. However, it
can be differentiated via the referencing instance. For a Book instance says aBook,
aBook.name refers to the name of the book; whereas for an Author's instance say
auAuthor, anAuthor.name refers to the name of the author. There is no need (and not
recommended) to call the variables bookName and authorName.
TRY:
1. Printing the name and email of the author from a Book instance. (Hint:
aBook.getAuthor().getName(), aBook.getAuthor().getEmail()).
2. Introduce new methods called getAuthorName(), getAuthorEmail(),
getAuthorGender() in the Book class to return the name, email and gender of the
author of the book. For example,
A class called MyPoint, which models a 2D point with x and y coordinates, is designed as
shown in the class diagram. It contains:
Two instance variables x (int) and y (int).
A "no-argument" (or "no-arg") constructor that construct a point at (0, 0).
A constructor that constructs a point with the given x and y coordinates.
Getter and setter for the instance variables x and y.
A method setXY() to set both x and y.
A toString() method that returns a string description of the instance in the format
"(x, y)".
A method called distance(int x, int y) that returns the distance from this point to
another point at the given (x, y) coordinates.
An overloaded distance(MyPoint another) that returns the distance from this point
to the given MyPoint instance another.
You are required to:
1. Write the code for the class MyPoint. Also write a test program (called
TestMyPoint) to test all the methods defined in the class.
Hints:
3. public double distance(int x, int y) { // this version takes two ints as arguments
7. }
8.
11. .......
12. }
13.
17. ......
.....
21. Write a program that allocates 10 points in an array of MyPoint, and initializes to
(1, 1), (2, 2), ... (10, 10).
Hints: You need to allocate the array, as well as each of the ten MyPoint
instances.
22. MyPoint[] points = new MyPoint[10]; // Declare and allocate an array of MyPoint
Notes: Point is such a common entity that JDK certainly provided for in all flavors.
1.4 Exercise: The MyCircle Class
A class called MyCircle, which models a circle with a center (x, y) and a radius, is
designed as shown in the class diagram. The MyCircle class uses an instance of MyPoint
class (created in the previous exercise) as its center.
The class contains:
Two private instance variables: center (an instance of MyPoint) and radius (int).
A constructor that constructs a circle with the given center's (x, y) and radius.
An overloaded constructor that constructs a MyCircle given a MyPoint instance as
center, and radius.
Various getters and setters.
A toString() method that returns a string description of this instance in the format
"Circle @ (x, y) radius=r".
A getArea() method that returns the area of the circle in double.
Write the MyCircle class. Also write a test program (called TestMyCircle) to test all the
methods defined in the class.
A method equals(double real, double imag) that returns true if this complex number
is equal to the given complex number of (real, imag).
An overloaded equals(MyComplex another) that returns true if this complex
number is equal to the given MyComplex instance another.
A method magnitude()that returns the magnitude of this complex number.
Note: The Math library has two arc-tangent methods, Math.atan(double) and
Math.atan2(double, double). We commonly use the Math.atan2(y, x) instead of
Math.atan(y/x) to avoid division by zero. Read the documentation of Math class in
package java.lang.
A method conjugate() that returns a new MyComplex instance containing the
complex conjugate of this instance.
conjugate(x+yi) = x - yi
Hint:
return new MyComplex(real, -imag); // construct a new instance and return the
constructed instance
Hint:
return this; // return "this" instance
You are required to:
1. Write the MyComplex class.
2. Write a test program to test all the methods defined in the class.
3. Write an application called MyComplexApp that uses the MyComplex class. The
application shall prompt the user for two complex numbers, print their values,
check for real, imaginary and equality, and carry out all the arithmetic operations.
4. Enter complex number 1 (real and imaginary part): 1.1 2.2
6.
10.
14.
Take note that there are a few flaws in the design of this class, which was introduced
solely for teaching purpose:
Comparing doubles in equal() using "==" may produce unexpected outcome. For
example, (2.2+4.4)==6.6 returns false. It is common to define a small threshold
called EPSILON (set to about 10^-8) for comparing floating point numbers.
The method add(), subtract(), and conjugate() produce new instances, whereas
multiplyWith() and divideBy() modify this instance. There is inconsistency in the
design (introduced for teaching purpose).
Unusual to have both argumentInRadians() and argumentInDegrees().
1.7 Exercise: The MyPolynomial Class
A class called MyPolynomial, which models polynomials of degree-n (see equation), is
designed as shown in the class diagram.
......
// Test program
Another constructor that takes coefficients from a file (of the given filename),
having this format:
Degree-n(int)
c0(double)
c1(double)
......
......
cn-1(double)
cn(double)
(end-of-file)
Hints:
public MyPolynomial(String filename) {
Scanner in = null;
try {
} catch (FileNotFoundException e) {
e.printStackTrace();
import java.math.BigInteger
.......
A class called MyTime, which models a time instance, is designed as shown in the class
diagram.
It contains the following private instance variables:
hour: between 0 to 23.
minute: between 0 to 59.
Second: between 0 to 59.
The constructor shall invoke the setTime() method (to be described later) to set the
instance variable.
It contains the following public methods:
setTime(int hour, int minute, int second): It shall check if the given hour, minute
and second are valid before setting the instance variables.
(Advanced: Otherwise, it shall throw an IllegalArgumentException with the
message "Invalid hour, minute, or second!".)
Setters setHour(int hour), setMinute(int minute), setSecond(int second): It shall
check if the parameters are valid, similar to the above.
Getters getHour(), getMinute(), getSecond().
toString(): returns "HH:MM:SS".
nextSecond(): Update this instance to the next second and return this instance.
Take note that the nextSecond() of 23:59:59 is 00:00:00.
nextMinute(), nextHour(), previousSecond(), previousMinute(), previousHour():
similar to the above.
Write the code for the MyTime class. Also write a test program (called TestMyTime) to
test all the methods defined in the MyTime class.
Write a test program that tests the nextDay() in a loop, by printing the dates from 28 Dec
2011 to 2 Mar 2012.
1.11 Exercise: Book and Author Classes Again - An Array of Objects as
an Instance Variable
In the earlier exercise, a book is written by one and only one author. In reality, a book can
be written by one or more author. Modify the Book class to support one or more authors
by changing the instance variable authors to an Author array. Reuse the Author class
written earlier.
Notes:
The constructors take an array of Author (i.e., Author[]), instead of an Author
instance.
The toString() method shall return "book-name by n authors", where n is the
number of authors.
A new method printAuthors() to print the names of all the authors.
You are required to:
1. Write the code for the Book class. You shall re-use the Author class written
earlier.
2. Write a test program (called TestBook) to test the Book class.
Hints:
System.out.println(javaDummy); // toString()
javaDummy.printAuthors();
In the above exercise, the number of authors cannot be changed once a Book instance
is constructed. Suppose that we wish to allow the user to add more authors (which is
really unusual but presented here for academic purpose).
We shall remove the authors from the constructors, and add a new method called
addAuthor() to add the given Author instance to this Book.
We also need to pre-allocate an Author array, with a fixed length (says 5 - a book is written
by 1 to 5 authors), and use another instance variable numAuthors (int) to keep track of
the actual number of authors.
You are required to:
1. Modify your Book class to support this new requirement.
Hints:
4. private Author[] authors = new Author[5]; // declare and allocate the array
7.
8. ......
9. ......
10.
13. ++numAuthors;
14. }
15. }
16.
21. javaDummy.printAuthors();
22.
javaDummy.printAuthors();
Δx = d × cos(θ)
Δy = -d × sin(θ)
x += Δx
y += Δy
reflectHorizontal() which reflects the ball horizontally (i.e., hitting a vertical wall)
Δx = -Δx
Δy no changes
Δx no changes
Δy = -Δy
toString() which prints the message "Ball at (x, y) of velocity (Δx, Δy)".
Write the Ball class. Also write a test program to test all the methods defined in the class.
A class called Container, which represents the enclosing box for the ball, is designed as
shown in the class diagram. It contains:
Instance variables (x1, y1) and (x2, y2) which denote the top-left and bottom-right
corners of the rectangular box.
A constructor which accepts (x, y) of the top-left corner, width and height as
argument, and converts them into the internal representation (i.e., x2=x1+width-
1). Width and height is used in the argument for safer operation (there is no need
to check the validity of x2>x1 etc.).
A toString() method that returns "Container at (x1,y1) to (x2, y2)".
A boolean method called collidesWith(Ball), which check if the given Ball is outside
the bounds of the container box. If so, it invokes the Ball's reflectHorizontal() and/or
reflectVertical() to change the movement direction of the ball, and returns true.
ball.reflectHorizontal();
return true;
......
ball.move();
box.collidesWith(ball);
In this exercise, a subclass called Cylinder is derived from the superclass Circle as shown
in the class diagram (where an an arrow pointing up from the subclass to its superclass).
Study how the subclass Cylinder invokes the superclass' constructors (via super() and
super(radius)) and inherits the variables and methods from the superclass Circle.
You can reuse the Circle class that you have created in the previous exercise. Make sure
that you keep "Circle.class" in the same directory.
public Cylinder() {
height = 1.0;
this.height = height;
this.height = height;
return height;
return getArea()*height;
Write a test program (says TestCylinder) to test the Cylinder class created, as follow:
System.out.println("Cylinder:"
System.out.println("Cylinder:"
System.out.println("Cylinder:"
Method Overriding and "Super": The subclass Cylinder inherits getArea() method
from its superclass Circle. Try overriding the getArea() method in the subclass Cylinder
to compute the surface area (=2π×radius×height + 2×base-area) of the cylinder instead
of base area. That is, if getArea() is called by a Circle instance, it returns the area. If
getArea() is called by a Cylinder instance, it returns the surface area of the cylinder.
If you override the getArea() in the subclass Cylinder, the getVolume() no longer works.
This is because the getVolume() uses the overridden getArea() method found in the same
class. (Java runtime will search the superclass only if it cannot locate the method in this
class). Fix the getVolume().
Hints: After overridding the getArea() in subclass Cylinder, you can choose to invoke the
getArea() of the superclass Circle by calling super.getArea().
TRY:
Provide a toString() method to the Cylinder class, which overrides the toString() inherited
from the superclass Circle, e.g.,
@Override
}
Override the toString() method to return "A Square with side=xxx, which is a
subclass of yyy", where yyy is the output of the toString() method from the
superclass.
Do you need to override the getArea() and getPerimeter()? Try them out.
Override the setLength() and setWidth() to change both the width and length, so
as to maintain the square geometry.
3. Exercises on Composition vs Inheritance
They are two ways to reuse a class in your applications: composition and inheritance.
3.1 Exercise: The Point and Line Classes
Let us begin with composition with the statement "a line composes of two points".
Complete the definition of the following two classes: Point and Line. The class Line
composes 2 instances of class Point, representing the beginning and ending points of the
line. Also write test classes for Point and Line (says TestPoint and TestLine).
// Private variables
// Constructor
// Public methods
System.out.println(p1);
......
// Constructors
public Line (Point begin, Point end) { // caller to construct the Points
this.begin = begin;
......
public Line (int beginX, int beginY, int endX, int endY) {
......
// Public methods
public String toString() { ...... }
// Math.sqrt(xDiff*xDiff + yDiff*yDiff)
// Math.atan2(yDiff, xDiff)
System.out.println(l1);
System.out.println(l2);
...
Instead of composition, we can design a Line class using inheritance. Instead of "a line
composes of two points", we can say that "a line is a point extended by another point", as
shown in the following class diagram:
Let's re-design the Line class (called LineSub) as a subclass of class Point. LineSub
inherits the starting point from its superclass Point, and adds an ending point. Complete
the class definition. Write a testing class called TestLineSub to test LineSub.
// Private variables
// Constructors
public LineSub (int beginX, int beginY, int endX, int endY) {
public LineSub (Point begin, Point end) { // caller to construct the Points
this.end = end;
// Public methods
Summary: There are two approaches that you can design a line, composition or
inheritance. "A line composes two points" or "A line is a point extended with another
point"”. Compare the Line and LineSub designs: Line uses composition and LineSub uses
inheritance. Which design is better?
3.2 Exercise: Circle and Cylinder using Composition
Try rewriting the Circle-Cylinder of the previous exercise using composition (as shown in
the class diagram) instead of inheritance. That is, "a cylinder is composed of a base circle
and a height".
public Cylinder() {
height = 1.0;
......
System.out.println(s1.getColor());
System.out.println(s1.isFilled());
System.out.println(s1.getRadius());
System.out.println(c1);
System.out.println(c1.getArea());
System.out.println(c1.getPerimeter());
System.out.println(c1.getColor());
System.out.println(c1.isFilled());
System.out.println(c1.getRadius());
System.out.println(s3.getArea());
System.out.println(s3.getPerimeter());
System.out.println(s3.getColor());
System.out.println(s3.getLength());
System.out.println(r1);
System.out.println(r1.getArea());
System.out.println(r1.getColor());
System.out.println(r1.getLength());
System.out.println(s4);
System.out.println(s4.getArea());
System.out.println(s4.getColor());
System.out.println(s4.getSide());
Rectangle r2 = (Rectangle)s4;
System.out.println(r2);
System.out.println(r2.getArea());
System.out.println(r2.getColor());
System.out.println(r2.getSide());
System.out.println(r2.getLength());
// Downcast Rectangle r2 to Square
System.out.println(sq1);
System.out.println(sq1.getArea());
System.out.println(sq1.getColor());
System.out.println(sq1.getSide());
System.out.println(sq1.getLength());
@Override
System.out.println("Meow!");
@Override
System.out.println("Woof!");
}
public void greeting(Dog another) {
System.out.println("Woooooooooof!");
@Override
System.out.println("Woow!");
@Override
System.out.println("Woooooowwwww!");
Explain the outputs (or error) for the following test program.
cat1.greeting();
dog1.greeting();
bigDog1.greeting();
// Using Polymorphism
animal1.greeting();
animal2.greeting();
animal3.greeting();
// Downcast
dog2.greeting(dog3);
dog3.greeting(dog2);
dog2.greeting(bigDog2);
bigDog2.greeting(dog2);
bigDog2.greeting(bigDog1);
......
For the MovablePoint class, declare the instance variable x, y, xSpeed and ySpeed with
package access as shown with '~' in the class diagram (i.e., classes in the same package
can access these variables directly). For the MovableCircle class, use a MovablePoint to
represent its center (which contains four variable x, y, xSpeed and ySpeed). In other
words, the MovableCircle composes a MovablePoint, and its radius.
public class MovablePoint implements Movable { // saved as "MovablePoint.java"
// instance variables
// Constructor
this.x = x;
......
......
@Override
......
// instance variables
// Constructor
......
......
@Override
center.y -= center.ySpeed;
......
System.out.println(m1);
m1.moveLeft();
System.out.println(m1);
System.out.println(m2);
m2.moveRight();
System.out.println(m2);
4. ......
5. Write the implementation class Circle, with a protected variable radius, which
implements the interface GeometricObject.
Hints:
7. // Private variable
8. ......
9.
10. // Constructor
11. ......
12.
14. @Override
16.
17. ......
18. Write a test program called TestCircle to test the methods defined in Circle.
19. The class ResizableCircle is defined as a subclass of the class Circle, which also
implements an interface called Resizable, as shown in class diagram. The
interface Resizable declares an abstract method resize(), which modifies the
dimension (such as radius) by the given percentage. Write the interface
Resizable and the class ResizableCircle.
Hints:
// Constructor
super(...);
@Override
public double resize(int percent) { ...... }
22. Write a test program called TestResizableCircle to test the methods defined in
ResizableCircle.
5. More Exercises on OOP
5.1 Exercise: The Discount System
You are asked to write a discount system for a beauty saloon, which provides services
and sells beauty products. It offers 3 types of memberships: Premium, Gold and Silver.
Premium, gold and silver members receive a discount of 20%, 15%, and 10%,
respectively, for all services provided. Customers without membership receive no
discount. All members receives a flat 10% discount on products purchased (this might
change in future). Your system shall consist of three classes: Customer, Discount and
Visit, as shown in the class diagram. It shall compute the total bill if a customer purchases
$x of products and $y of services, for a visit. Also write a test program to exercise all the
classes.
The class DiscountRate contains only static variables and methods (underlined in the
class diagram).
5.2 Exercise: Polyline of Points with ArrayList
A polyline is a line with segments formed by points. Let's use the ArrayList (dynamically
allocated array) to keep the points, but upcast to List in the instance variable. (Take note
that array is of fixed-length, and you need to set the initial length).
private int x;
private int y;
import java.util.*;
this.points = points;
points.add(newPoint);
}
// Append a point instance to the end of this polyline
points.add(point);
// return (x1,y1)(x2,y2)(x3,y3)....
sb.append(aPoint.toString());
return sb.toString();
System.out.println(l1); // empty
l1.appendPoint(2, 2);
l1.appendPoint(3, 3);
System.out.println(l1); // (1,1)(2,2)(3,3)
Try:
1. Modify the push() method to throw an IllegalStateException if the stack is full.
2. Modify the push() to return true if the operation is sucessful, or false otherwise.
3. Modify the push() to increase the capacity by reallocating another array, if the
stack is full.
Exercise (Nodes, Link Lists, Trees, Graphs):
[TODO]
Study the existing open source codes, including JDK.
Specialized algorithms, such as shortest path.
Exercise (Maps):
[TODO]
Representation of map data.
Specialized algorithms, such as shortest path.