INFORMATION & COMPUTER SCIENCE DEPARTMENT, KFUPM

ICS102, SECTIONS 52, 54 & 55  (001 Semester)

INTRODUCTION TO COMPUTING

LAB  #09 Classes and Type definitions

 

Instructor: Bashir M. Ghandi

 


Objectives:

To gain experience with:

 

1.  Classes as types

Most of the times we would like our classes to behave as types.  That is, we would like to create more than one object (instance) of a given class, with each object having the fields and/or methods defined in the class. 

 

For example, just like we would like to define more than one integer variable:           int n1, n2;

We would like to create more than one Point objects (say) from the Point class:  Point p1, p2;

 

We saw in the last Lab that to be able to do this, we must declare fields and methods as non-static. 

We also saw that we need to have constructors, which are used to create and initialize objects, since unlike primitive variables which are initialized directly as in:      

n1=10;   n2=15;

Objects are initialized using a constructor and the new keyword as in:

p1 = new Point(10, 7);

p2 = new Point(20, 8);

 

Example1:  The following defines a Point class, which can then be used to create a Point object.

class Point {
        private double x;
        private double y;
        
        public Point(double x1, double y1) {
               x=x1;
               y=y1;
        }
        
        public double distanceToOrigin() {
               return Math.sqrt((x * x) + (y * y));
        }
        
        public double distanceToPoint(Point p) {
               return Math.sqrt(((x - p.x)*(x - p.x))+((y - p.y)*(y - p.y)));
        }
        
        public void moveTo(double x1, double y1) {
               x=x1;
               y=y1;
        }
        
        public void translate(double dx, double dy) {
               x += dx;
               y += dy;
        }
        
        public double getX() {
               return x;
        }
        
        public  double getY() {
               return y;
        }
}

Notes:

·         When defining a class, we should implement all the methods of the class that we can think of, including those that are not needed in our current application.  This allows the class to be reused in other applications.  Reusability is one of the most important advantages of Java.

·         The fields of a class are usually declared as private so that they can only be modified by methods of the particular object.  This ensures integrity and security of the object. Imagine another customer being able to withdraw from your account!

·         Methods can be declared before or after the fields in a class.

·         Methods that modify the fields of an object are called mutator methods. Example are: moveTo and translate.

·         Methods that do not modify the fields but only access them to compute and return some result are called accessor methods.  Example: getX, getY, distanceToPoint & distanceToOrigin

 

Before we see how the above class may be used in an application, let us introduce two important things that are very useful when designing a class; overloading and the this keyword.

 

Overloading:

It is possible to have more than one constructor in a class (of course with the same name as the class) provided each has different signature (i.e. different number or types of parameters).  This is called overloading.  For example, another constructor for the Point class might be:

public Point() {

    x=0;

    y=0;

}

 

A constructor that does not have any parameter such as the above is called the default constructor.  If a default constructor is not defined, the compiler automatically creates one that initializes the fields to their default values as show by the table below.

Type

Default Value

boolean

false

byte

(byte) 0

short

(short) 0

int

0

long

0L

char

\u0000

float

0.0f

double

0.0d

object reference

null

Note that local variables (those declared in a method) are not initialized automatically.

 

Overloading is also allowed on methods.  We can have methods with the same name provided the signature is different.  For example all the following max methods could be defined in the same class.

 

public static double max(double a, double b) {
  if (a >= b)
    return a;
  else
    return b;
 
} 
public static String max(String a, String b) {
  if (a.compareTo(b) > 0)
    return a;
  else
    return b;
 
} 
public static Point max(Point a, Point b) {
  if (a.distanceToOrigin() > b.distanceToOrigin())
    return a;
  else
    return b;
} 

The this keyword

In the definition of the constructor, we have to use x1 and y1 as parameters.

        public Point(double x1, double y1) {
               x=x1;
               y=y1;
        }

 

This is because, if we were to use x and y then we cannot access the fields of the object which are also x and y.  To solve this problem, java provides the this keyword which is used as a reference to the current object.  Thus, this.x means the object variable x.  We can therefore modify the above method as:

        public Point(double x, double y) {
               this.x=x;
               this.y=y;
        }

 

The this keyword can also be used to refer to methods of this object.  It is in fact a common practice to use this to create another constructor using another.  For example, the default constructor of the Point class can be implemented by calling the other constructor as follows:                    public Point() {

    this(0.0, 0.0);

}

 

With these modifications, the Point class is updated as follows:

class Point {

      private double x;

      private double y;

      

      public Point(double x, double y) {

            this.x=x;

            this.y=y;

      }

     

      public Point() {

            this(0.0, 0.0);

      }

     

      public double distanceToOrigin() {

            return Math.sqrt((x * x) + (y * y));

      }

     

      public double distanceToPoint(Point p) {

            return Math.sqrt(((x - p.x) * (x - p.x)) + ((y - p.y) * (y - p.y)));

      }

     

      public void moveTo(double x, double y) {

            this.x=x;

            this.y=y;

      }

     

      public void translate(double dx, double dy) {

            x += dx;

            y += dy;

      }

     

      public double getX() {

            return x;

      }

     

      public  double getY() {

            return y;

      }

     

      public String toString() {

            return "("+x+", "+y+")";

      }

     

      public boolean equals(Point p) {

            return (this.x == p.x && this.y == p.y);

      }

}

 

toString and equals method.

Every object has a default toString and equals methods.  The toString is used to convert an object to string.  The toString method is automatically invoked when the object is used where a string is expected, example in println method.  You can specify how an object is printed by re-defining its toString method.

 

Similarly, the equals method is used to compare the current object with another object of the same class.  It is important to note that objects are not compared using the == operator, as this only compares the references of the two objects and not the actual objects.  Again one can override the default equals method by defining one in the class.

 

Example 2: The following example shows how the Point class may be used:

import TextIO;

 

class TestPoint {

      static TextIO stdin = new TextIO(System.in);

     

      public static void main(String[] args) throws java.io.IOException{

        

         double x,y;

        

         System.out.print("Enter first point: ");

         x=stdin.readDouble();

         y=stdin.readDouble();

         Point p1 = new Point(x,y);

           

         System.out.print("Enter second point: ");

         x=stdin.readDouble();

         y=stdin.readDouble();

         Point p2 = new Point(x,y);

        

         System.out.println("Distance of "+p1+ " to origin = "+p1.distanceToOrigin());

         System.out.println("Distance of "+p2+ " to origin = "+p2.distanceToOrigin());

         System.out.println("Distance between "+p1+" and "+p2+ " = "+p1.distanceToPoint(p2));

      }

}

 

Note that in the println() statements above, each time we have . . +p1+ . .  the toString() method is called to convert p1 to String.

 

Example 3: The following implements an Account class.

class Account {

      private static int numberOfAccounts = 0; //this belongs to the class

     

      private double balance;

      private int accountNumber;

      private String holdersName;

     

      public Account(String holdersName, double amount) {

            if (amount >= 0)

                balance = amount;

            numberOfAccounts++;

            accountNumber=numberOfAccounts;

            this.holdersName = holdersName;

      }

     

      public Account(String holdersName) {  //in case no initial amount is given

            this(holdersName, 0);

      }

     

      public Account(double amount, String holdersName) { //if amount is given first

            this(holdersName, amount);

      }

     

      public void deposit(double amount) {

            if (amount > 0)

               balance+=amount;

      }

     

      public void withdraw(double amount) {

            if (amount <= balance)

                balance-=amount;

      }

     

      public void transferTo(Account account, double amount) {

            if (amount < balance && amount > 0) {

                  withdraw(amount);

                  account.deposit(amount);

            }

      }

     

      public void showBalance() {

            System.out.println("\nAcc#: "+accountNumber);

            System.out.println("Holder's Name: "+holdersName);

            System.out.println("Balance: "+balance);

      }

     

      public String toString() {

            return "\nAcc#: "+accountNumber+"\nHolder's Name: "+holdersName+"\nBalance: "+balance;

      }

}

 

Note: It does not make sense for the number of accounts to belong to an object.  There should be only one copy of this, so it is declared as static (i.e. it belongs to the class).

 

Example 4:  The following shows how the Account class may be used.

import TextIO;

 

class TestAccount {

      static TextIO stdin = new TextIO(System.in);

     

      public static void main(String[] args) throws java.io.IOException{

           

            double amount;

            String name;

           

            System.out.print("Enter name of first Customer: ");

            name=stdin.readString();

            System.out.print("Enter initial amount: ");

            amount=stdin.readDouble();

            Account acc1 = new Account(name,amount);

           

            System.out.print("Enter name of second customer: ");

            name=stdin.readString();

            Account acc2 = new Account(name);

           

            acc1.showBalance();

            acc2.showBalance();

           

            System.out.print("\nEnter amount to transfer : ");

            amount=stdin.readDouble();

           

            acc1.transferTo(acc2,amount);

            acc1.showBalance();

            acc2.showBalance();

            System.out.println(acc1);

      }

}

 


2.  Assignments

1.       Implement a class Employee with the following fields, constructors and methods:

Fields:

                name;

                salary;

Constructors:

                public Employee(String name, double salary)

                public Employee(double salary, String name)

                public Employee(String name)  //this should initialize the salary to 0.0

Methods:

                public String getName()

                public double getSalary()

                public void raiseSalary(double percentageIncrease)

                public void printEmployee()  //prints the employee’s name and Salary

                public String toString()

 

Write an application TestEmployee that reads the names and salaries of two employees and make use of the Employee class to create two Employee objects and print them.  Next, read a percentage increase in salary for each employee and call the raiseSalary() method  to increment each and print the objects again.

2.        Implement a Student class with the following fields, constructors and methods:

Fields:

                name;

                totalScore;

                numberOfQuizzes;

Constructors:

                public Student(String name, double score)

                public Student(double score, String name)

                public Student(String name) {

Methods:

                public String getName()

                public double getAverage()       //this should return zero if no quiz has been taken.

                public double getTotalScore()

                public void addQuiz(double score)

                public void printStudent()          //this should print the student’s name and average score

                public String toString()

 

Write an application TestStudent that reads a student name and use the Student class to create a Student object.  Then read the scores of the student in three quizzes and add each to the totalScore of the student using addQuiz() method and print the student object.

 

3.  Home Work

Implement a Fraction class with the following fields, constructors and methods.

Fields:

numerator

denominator

Constructors:

public Fraction(int numerator, int denominator) //this should make use of gcd to reduce the fraction to simplest form

public Fraction(int numerator)  //initializes denominator to 1

public Fraction()  //initialize numerator to zero and denominator to 1

Methods:

private static gcd(int n, int m)  //returns the greatest common divisor of n and m.

public void setValue(int numerator, int denominator) //this should make use of gcd to reduce the fraction to simplest form

public void setValue(Fraction f)

public int getNumerator()

public int getDenominator()

public double toDouble()

public String toString()  //should return the fraction in the form: “numerator / denominator”

public boolean equals(Fraction f)

public Fraction reduce(Fraction f) //reduces a fraction to its simplest form –divide both values by their gcd.

public Fraction add(Fraction f)  //Hint:  a/b + c/d  =  (a*d + c*b)/(b*d)

public Fraction multiply(Fraction f)

public Fraction divide(Fraction f)

Note: The methods, add, multiply and divide should return the Fraction in its simplest form.

 

Now to test your Fraction class, write a menu-driven application, TestFraction, that reads two fractions and perform the selected operation.