Universidad Carlos III de Madrid

Ingeniería de Telecomunicación

Enero-Mayo 2010 / January-May 2010

Object-Orientation & Inheritance

Lab Section1.  Session 2 (lab): Object-Orientation & Inheritance (I)

Exercise Section1.1. Points and Figures (I)

The Point class.

A point at the plane can be represented by a pair of coordinates x and y, both with real values. In Java, we can represent a point at the plane as an instance of the following class:

public class Point {
    private double x;
    private double y;

    /* methods */
    /* to complete */
}
Class constructor.

In Java, the constructor of a class is used to initialise the values of the attributes at the moment the object is instantiated at runtime execution.

  1. Program a constructor for the Point class. It must receive both point coordinates as input parameters.

Method to get a text representation of the object.

The toString() method has a special meaning for objects in Java. This method is used to get a text representation of the object as a string.

  1. Program the toString() method so that it returns a string with the representation of the point according to the following format:

    (x, y)

    where x and y must be replaced by their respectives values. The prototype of the method is specified as follows:

    public String toString() {
        /* ... */
    }

    Hint

    Remember that the "+" operator, applied to strings of characters, allows to concatenate them. But if you try to concatenate a number with a string, don't worry, Java converts automaticaly the number to a string to make the "addition".

The main method.

Now you have to create a class to test the previous code.

  1. Program a class called TestingPoint which has a main method. This method must receive, as command line arguments, the x and y coordinates, then create a new Point object with those coordinates and print a text representation of such object to the standard output (the console).

    The program must check that the number of command line arguments received is correct.

    Hint

    The parseDouble() method of the Double class (click to follow the link to the API Javadoc) transforms a string of characters to a double primitive type.

The access methods.

It is common that object's attributes are declared as private (private) to avoid uncontrolled accesses from other parts of the code. To provide such access from outside code, there are special methods. Those methods usually begin with the following strings: "get" (read access) and "set" (write access).

  1. Program the following access methods that return the coordintate values x and y in the Point class. The prototype of those methods is shown below:

    public double getX() {
        /* ... */
    }
    
    public double getY() {
        /* ... */
    }
  2. Modify the code of your TestingPoint class to check that its behaviour is correct.

Distance calculation.

In this paragraph, we are going to implement two auxiliary methods that will allow us to calculate distances between points.

  1. Program a method of the Point class that returns the distance from the point to the origin of the coordinates. The prototype of the method is as follows:

    public double distanceToOrigin() {
    /*  complete */
    }

    Modify the code of your TestingPoint class to check that its behaviour is correct.

  2. Program a method of the Point class that returns the distance between the point represented by the actual object instance and another instance of Point that is received as input parameter. The prototype of the method is as follows:

    public double distance(Point anotherPoint) {
        /* completar */
    }

    Modify the code of your TestingPoint class to check that its behaviour is correct.

Quadrant calculation.
  1. Program a method of the Point class that returns the quadrant in which the point is located. The prototype of the method is as follows:

    • It returns 0 if it is placed at the origin of coordinates or on any of the axis.

    • It returns 1 if it is placed at the first quadrant (both x and y positives).

    • It returns 2 if it is placed at the second quadrant (x negative and y positive).

    • It returns 3 if it is placed at the third quadrant (both x and y negatives).

    • It returns 4 if it is placed at the fourth quadrant (x positive and y negative).

    The prototype of the method is shown below:

    public int quadrant()  {
      /* complete */
    }

    Modify the code of your TestingPoint class to check that its behaviour is correct.

Nearest point calculation.

This section is based on the previous methods you have implemented before.

  1. Program a method of the Point class that receives, as input parameter, an array of Point objects and returns a reference to the object of the array that represents the nearest point to the current object (this). The prototype of the method is as follows:

    public Point nearest(Point[] otherPoints) {
      /* complete */
    }

    Modify the code of your TestingPoint class to check that its behaviour is correct.

The Triangle class.

A triangle is fully defined by three of its vertexes. These vertexes can be represented as objects of the Point class.

Class declaration.

This section is based on the previous methods you have implemented before.

  1. Program the Triangle class with its attributes and a constrctor that receives three points (vertexes) as input parameters.

Side length calculation.

Program a class to test it.

  1. Program the edgesLength() method of the Triangle class. It must return an array of three decimals (double) that represents, respectively, the length of each side of the triangle. The prototype of the method is as follows:

    public double[] edgesLength() {
        /* complete... */
    }

Solutions

The solutions of this exercise are included in the following listings:

// Point class
// (c) 2008 IT

public class Point {
  private double x;
  private double y;

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

  /**
   * Returns the coordinates of the point in a string
   */
  public String toString() {
    // '+' operator in String objects does not mean mathematical sum, but
    // concatenation of strings
    return "(" + x + ", " + y + ")";
  }

  /**
   * Returns the distance to the origin
   */
  public double distanceToOrigin() {
    // It can be also calculated calling to
    // distance(new Point(0,0))
    return Math.sqrt(x * x + y * y);
  }

  /* Getter methods */
  public double getX() {
    return x;
  }

  public double getY() {
    return y;
  }

  /** Returns the distance to another point */
  public double distance(Point anotherPoint) {
    double x1;
    double y1;

    x1 = x - anotherPoint.getX();
    y1 = y - anotherPoint.getY();
    return Math.sqrt(x1 * x1 + y1 * y1);
  }

  /** Returns the quadrant */
  public int quadrant() {
    if (x > 0.0 && y > 0.0) {
      return 1;
    } else if (x < 0.0 && y > 0.0) {
      return 2;
    } else if (x < 0.0 && y < 0.0) {
      return 3;
    } else if (x > 0.0 && y < 0.0) {
      return 4;
    } else {
      // (x==0.0 || y==0.0)
      return 0;
    }
  }

  /**
   * Returns the nearest point of the array in the parameter or null if array is
   * empty
   * 
   * @param otherPoints
   * @return
   */
  public Point nearest(Point[] otherPoints) {
    Point nearestPoint = null;
    double minDistance;
    double distance;

    if (otherPoints != null && otherPoints.length > 0) {
      // Start storing the first point in the array as the nearest one
      minDistance = distance(otherPoints[0]);
      nearestPoint = otherPoints[0];

      for (int i = 1; i < otherPoints.length; i++) {
        // If nearer point is found, this is the new nearest one
        distance = distance(otherPoints[i]);
        if (distance < minDistance) {
          distance = minDistance;
          nearestPoint = otherPoints[i];
        }
      }
    }

    return nearestPoint;
  }
}

	  
// TestingPoint
// (c) 2007 IT
public class TestingPoint {

  public static void main(String args[]) {

    // Check the number of arguments (the two coordinates)
    if (args.length != 2) {
      System.out.println("Usage:");
      System.out.println("  java TestingPoint x y");
      System.out.println("where x and y are the coordinates of a point.");
      return;
    }

    // Handle exceptions
    try {
      double x = Double.parseDouble(args[0]);
      double y = Double.parseDouble(args[1]);

      Point p = new Point(x, y);
      System.out.println("The point is " + p.toString());
      System.out.println("Its distance to origin is " + p.distanceToOrigin());
      System.out.println("Its X coordinate is " + p.getX()
          + " and its Y coordinate is " + p.getY());

      System.out.println("It is located in the quadrant" + p.quadrant());

      Point[] pointsArray = new Point[5];
      pointsArray[0] = new Point(1, 1);
      pointsArray[1] = new Point(5, 3);
      pointsArray[2] = new Point(10, 10);
      pointsArray[3] = new Point(-3, 2);
      pointsArray[4] = new Point(-4, -5);

      for (int i = 0; i < pointsArray.length; i++) {
        System.out.println("Its distance to the point "
            + pointsArray[i].toString() + " is " + p.distance(pointsArray[i]));
      }
      System.out.println("The nearest point is " + p.nearest(pointsArray));
    } catch (Exception e) {
      System.out.println("Error in the arguments of the command line.");
      return;
    }

  }
}
	  
// Testing triangle
// (c) 2007 IT
public class TestingTriangle {

  public static void main(String args[]) {

    // Checking number of arguments(Two coordinates for every point)
    if (args.length != 6) {
      System.out.println("Usage:");
      System.out.println("  java PruebaTriangulo x1 y1 x2 y2 x3 y3");
      System.out.println("where (xi,yi) are the coordinates of every vertex");
      return;
    }

    // Handle exceptions
    try {
      double x1 = Double.parseDouble(args[0]);
      double y1 = Double.parseDouble(args[1]);
      double x2 = Double.parseDouble(args[2]);
      double y2 = Double.parseDouble(args[3]);
      double x3 = Double.parseDouble(args[4]);
      double y3 = Double.parseDouble(args[5]);

      // Vertexes and the triangle are finally created
      Point v1 = new Point(x1, y1);
      Point v2 = new Point(x2, y2);
      Point v3 = new Point(x3, y3);
      Triangle t = new Triangle(v1, v2, v3);

      // Displaying the info
      System.out.println("The triangle has vertexes " + v1.toString() + ", "
          + v2.toString() + ", " + v3.toString());

      double[] edgesLength = t.edgesLength();
      System.out.println("Its edges are " + edgesLength[0] + ", "
          + edgesLength[1] + ", " + edgesLength[2] + " long");
    } catch (Exception e) {
      System.out.println("Error in the arguments of the command line");
      return;
    }

  }
}
	  
/**
 * Triangle.java
 * 
 * (c) DIT-UC3M 2008
 * 
 */

public class Triangle {

  /** Vertexes of the triangle */
  private Point vertex1;
  private Point vertex2;
  private Point vertex3;

  /** Constructor of a triangle with their vertexes */
  public Triangle(Point vertex1, Point vertex2, Point vertex3) {

    this.vertex1 = vertex1;
    this.vertex2 = vertex2;
    this.vertex3 = vertex3;

  }

  /** Returns an array with the length of every edge of the triangle */
  public double[] edgesLength() {
    double edgesLength[] = new double[3];

    // Length 1->2
    edgesLength[0] = vertex1.distance(vertex2);
    // Length 2->3
    edgesLength[1] = vertex2.distance(vertex3);
    // Length 3->1
    edgesLength[2] = vertex3.distance(vertex1);

    return edgesLength;
  }
}

	  

Homework Section2.  Homework

Exercise Section2.1. Exercise to practice with Dates

In this execise, we are going to create a Date class that will allow us to work with dates. This class has to store some attributes and must define some methods that will make different basic operations.

Before start writing the code, try to think about the design of Date class.

  1. What kind of information must be stored in each object? If some given data can be stored in different formats, would you use several attributes to represent the same information? Why? Which format do you think is more appropriate?

  2. What constructors would you provide? Notice that constructors have to initialize the internal object data.

  3. Think of what methods you think would be useful to be included in the class.

  4. Can you think of any kind of information that could be suitable to be included in the class and that is common for all objects from Date?

Class attributes.

  1. Define all attributes for Date class.

Class constructors.

The Date class has to provide two constructors to initialize Date's objects.

  • A constructor with three integers that represent the day, month and year, respectively.

  • A constructor with three strings of characters that represent the day, month and year, respectively.

  1. Program these constructors according to the following declarations:

    public Date(int day, int month, int year) {
        /* complete */
    }
    
    public Date(String day, String month, String year) {
        /* complete */
    }
    

Access methods.

Object attributes should be declared with private access to avoid making errors in their updates. Program both get and set methods which are necesary to read and update encapsulated information of Date's objects.

A toString() method for a text representation of the object.

The toString() method has a special meaning for all objects in Java. It is used to get a String representation of the object that shows the values of the object's attributes at a given moment.

  1. Program the toString() method according to the following declaration:

    public String toString() {
        /* completar */
    }
    

    This method has to return a string of characters with a text representation of a date, according to the following format (don't worry about the ordinal ("21st", "13th"):

    month(text) day(number), year(number)

    EXAMPLE : August 6, 2007

The compareTo() method to compare dates.

The compareTo() method has a special meaning for objects in Java. It is used to compare two objects.

RECOMMENDED READING: Consult the Java API documentation of the comparation interface at the following link Comparable. In this page, look for what value must be returned in each case of comparation of the two objects.

  1. Program the compareTo() method according to the following declaration:

    public int compareTo(Date date) {
        /* ... */
    }
    

    This method compares the date stored in the current object with the date stored in the other object that is passed as input parameter and it must return:

    • -1 if the date stored in the current object is previous than the date stored in the object passed as parameter.

    • 0 if both dates are equal.

    • 1 if the date stored in the current object is later than the date stored in the object passed as parameter.

Overloaded auxiliary method.

Remember that a class can contain several methods with the same name, as long as they have distinct input parameters. This is known as method overloading.

  1. Program an auxiliary method that returns the number of days that the month that is passed by parameter has. Overload that method so that it can be used with either the number or the name of the month. Both methods have the following declarations:

    ... int getDaysInMonth(int month) {
        /* complete */
    }
    ... int getDaysInMonth(String month) {
        /* complete */
    }
    

Solution

The solution of these exercises are included in the following listings:

import java.io.*;

public class Date {

  /**
   * Months of the year in order, to facilitate the conversion to integer format
   * 
   * The number of the month is the same as the position of the name of the
   * month in this array plus 1. (because the positions in the array start in 0,
   * but months start in 1)
   */
  private static final String[] months = { "January", "February", "March",
      "April", "May", "June", "July", "August", "September", "October",
      "November", "December" };

  // ATTRIBUTES

  private int day;
  private int month;
  private int year;

  // CONSTRUCTORS

  public Date(int day, int month, int year) throws ExceptionDate {

    checkDate(day, month, year);

    this.day = day;
    this.month = month;
    this.year = year;

  }

  public Date(String sDay, String sMonthName, String sYear)
      throws ExceptionDate {

    // Convert strings to number
    try {
      day = Integer.parseInt(sDay);
      year = Integer.parseInt(sYear);

    } catch (NumberFormatException nfe) {
      // Error converting a string to a number
      throw new ExceptionDate("Wrong date");
    }

    month = getMonth(sMonthName);

    // Checking that values have sense
    checkDate(day, month, year);

  }

  // ACCESORS

  public int getDay() {
    return day;
  }

  public int getMonth() {
    return month;
  }

  public int getYear() {
    return year;
  }

  public void setDay(int day) throws ExceptionDate {
    checkDate(day, this.month, this.year);
    this.day = day;
  }

  public void setMonth(int month) throws ExceptionDate {
    checkDate(this.day, month, this.year);
    this.month = month;
  }

  public void setYear(int year) throws ExceptionDate {
    checkDate(day, month, year);
    this.year = year;
  }

  // METHODS

  public String toString() {
    return (day + " of " + months[month - 1] + ", " + year);
  }

  public int compareTo(Date date) {

    int result = 0;

    if (year < date.getYear()) {
      result = -1;
    } else if (year > date.getYear()) {
      result = 1;
    } else { // Years are the same => compare the months

      if (month < date.getMonth()) {
        result = -1;
      } else if (month > date.getMonth()) {
        result = 1;
      } else { // Months are the same => compare the days

        if (day < date.getDay()) {
          result = -1;
        } else if (day > date.getDay()) {
          result = 1;
        } else { // Days are also the same => same date
          result = 0;
        }
      }
    }

    return result;
  }

  // AUXILIAR METHODS

  /**
   * Returns the number of the days of a given month
   */
  private int getDaysFromMonth(int month) throws ExceptionDate {

    int monthDays = 0;

    switch (month) {

    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12: // months of 31 days
      monthDays = 31;
      break;

    case 4:
    case 6:
    case 9:
    case 11: // months of 30 days
      monthDays = 30;
      break;

    case 2: // February
      if (isLeapYear(year))
        monthDays = 29;
      else
        monthDays = 28;
      break;

    default: // Wrong month
      throw new ExceptionDate("Wrong month");
    }

    return monthDays;

  }

  /**
   * Returns the number of days of a given month
   */
  private int getDaysFromMonth(String month) throws ExceptionDate {
    return getDaysFromMonth(getMonth(month));
  }

  /**
   * Auxiliary method to get the number of a month, given its name. It returns
   * -1 if the text does not refers to any month.
   */
  private static int getMonth(String sMonthName) throws ExceptionDate {

    // Get the number of the month
    int month = -1;
    for (int i = 0; i < months.length && month == 0; i++) {
      if (months[i].equalsIgnoreCase(sMonthName)) {
        // The month referes to this element in the array
        month = i + 1;
      }
    }

    return month;
  }

  /**
   * Auxiliary method to check if a date is valid or not
   */
  private void checkDate(int day, int month, int year) throws ExceptionDate {

    // Check that the day is valid
    // (The getMonthDay already checks if the month is valid)
    if ((day <= 0) || (day > getDaysFromMonth(month))) {
      throw new ExceptionDate("Wrong date");
    }

  }

  /**
   * Checks if a year is a leap year A year is leap year if it is multiple of 4
   * and not multiple of 100, and the multiple of 400.
   */
  private boolean isLeapYear(int year) {
    return ((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0));
  }

  public static Date readDate() {

    BufferedReader entry = new BufferedReader(new InputStreamReader(System.in));
    Date date = null;
    String sDay, sMonth, sYear; // Variables to store the entry of the user
    int iMonth;

    boolean correct = false;

    do {

      try {

        System.out.print("Enter day: ");
        System.out.flush();
        sDay = entry.readLine();
        System.out.print("Enter month: ");
        System.out.flush();
        sMonth = entry.readLine();
        System.out.print("Enter year: ");
        System.out.flush();
        sYear = entry.readLine();

        // Check if the user has entered the name of the month
        iMonth = getMonth(sMonth);

        if (iMonth == -1) {
          // Check if the user has entered the number of the month
          iMonth = Integer.parseInt(sMonth);
        }

        date = new Date(sDay, months[iMonth], sYear);
        correct = true;

      } catch (Exception ex) {
        correct = false;
      }

    } while (!correct);

    return date;
  }

  public Date moreRecentDate(Date[] dates) {

    Date date = null;

    if ((dates != null) && (dates.length > 0)) {

      int max = 0;
      for (int i = 1; i < dates.length; i++) {
        if (dates[max].compareTo(dates[i]) < 0) {
          max = i;
        }
      }
      date = dates[max];
    }

    return date;

  }

}

	   
/**
 * Exception ExceptionDate is thrown when a Date object is created with wrong
 * data.
 */
public class ExceptionDate extends Exception {

  /**
   * Default constructor, creates an exception without a descriptive message.
   */
  public ExceptionDate() {
    super(); // invoke the constructor of the base class Exception
  }

  /**
   * Constructor with parameters, it creates an exception with a descriptive
   * message of the error.
   * 
   * @param message
   *          descriptive message of the error that creates the exception.
   */
  public ExceptionDate(String message) {
    super(message); // invoke the constructor of the base class Exception
  }
}			 
	 

Exercise Section2.2.  Object Oriented Programming, step by step

Classes and Object creation

Objective

Review class declaration and object creation.

Exercise

The Album class represents the production of a singer or musical groups. This class has the following attributes:

  • title: The Album title

  • author: The name of the singer or group

  • year: Publishing year

  • elements: Number of CDs or DVDs included in the Album

  • price: Suggested retail price (without VAT)

  • genre: A character indicating the type of genre (D: Dance, P: Pop, R: Rock, C: Classical, J: Jazz, O: Other)

  • isSpanish: True if it is an album of a Spanish singer or group

Think about the attributes, their data type and modifiers. Then implement the Album class in Java

Then implement a new class called AlbumTest that only contains the main method to test the Album class. This class has to:

  • Create two objects of type Album called album1 and album2

  • Assign a value to the attributes with data from two albums that you like

  • Print the information of each album correctly tabulated as shown below

               	Album:
    		Title:		Crazy Hits
    		Author:		Crazy Frog
    		Year:		2005
    		Num:		1
    		Price:		14.99
    		Genre:		D
    		Is Spanish?:	False
             

Solution

The solution is included in the following listings:

Album.java

public class Album { public String title; public String author; public int year; public int elements; public float price; public char genre; public boolean isSpanish; public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + price + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; // Object creation album1 = new Album(); album2 = new Album(); // assigning value to the attributes album1.title = "Crazy Hits"; album1.author = "Crazy Frog"; album1.year = 2005; album1.elements = 1; album1.price = 14.99f; album1.genre = 'D'; // album1.isSpanish=false; album2.title = "Cien gaviotas donde iran"; album2.author = "Varios"; album2.year = 2005; album2.elements = 1; album2.price = 14.99f; album2.genre = 'O'; album2.isSpanish = true; // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); } }

Access Methods

Objective

Review objects encapsulation and access to private attributes using public methods.

Exercise

Add the necessary get and set to assign and retrieve the value of each attribute. For the genre attribute, check that the character used is valid before assigning it.

Modify the main method of AlbumTest to use the access method defined above. Check the result.

Solution

The solution is included in the following listing:

Album.java

public class Album { private String title; private String author; private int year; private int elements; private float price; private char genre; private boolean isSpanish; public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setYear(int year) { this.year = year; } public void setElements(int elements) { this.elements = elements; } public void setPrice(float price) { this.price = price; } public void setGenre(char genre) { switch (genre) { case 'D': case 'P': case 'R': case 'C': case 'J': case 'O': this.genre = genre; break; default: System.out .println("The genre is not valid use one of the following characters: \n DANCE: D \n POP: P \n ROCK: R \n CLASSICAL: C \n JAZZ: J \n OTHER: O"); } } public void setIsSpanish(boolean isSpanish) { this.isSpanish = isSpanish; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } public int getElements() { return elements; } public float getPrice() { return price; } public char getGenre() { return genre; } public boolean getIsSpanish() { return isSpanish; } public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + price + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; // Object creation album1 = new Album(); album2 = new Album(); // assigning value to the attributes album1.setTitle("Crazy Hits"); album1.setAuthor("Crazy Frog"); album1.setYear(2005); album1.setElements(1); album1.setPrice(14.99f); album1.setGenre('D'); album1.setIsSpanish(false); album2.setTitle("Cien gaviotas donde iran"); album2.setAuthor("Varios"); album2.setYear(2005); album2.setElements(1); album2.setPrice(14.99f); album2.setGenre('O'); album2.setIsSpanish(true); // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); } }

Operators

Objective

Review arithmetic operators.

Exercise

Modify AlbumTest.java to calculate the total price of the albums (with and without VAT) and print a message on the screen like this:

	  Total price (without VAT):	29.98 euros
	  Total price (with 16% VAT):	34.7768 euros
	

Solution

The solution is included in the following listing:


AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; // Object creation album1 = new Album(); album2 = new Album(); // assigning value to the attributes album1.setTitle("Crazy Hits"); album1.setAuthor("Crazy Frog"); album1.setYear(2005); album1.setElements(1); album1.setPrice(14.99f); album1.setGenre('D'); album1.setIsSpanish(false); album2.setTitle("Cien gaviotas donde iran"); album2.setAuthor("Varios"); album2.setYear(2005); album2.setElements(1); album2.setPrice(14.99f); album2.setGenre('O'); album2.setIsSpanish(true); // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); System.out.println("Total price (without IVA): " + (album1.getPrice() + album2.getPrice())); System.out.println("Total price (with 16% IVA): " + (1.16 * (album1.getPrice() + album2.getPrice()))); } }

Constructors

Objective

Review constructors and their relationship to access methods.

Exercise

We have not written any constructor for the Album class yet. After creating an object of Album class, we have to call access methods such as setTitle or setAuthor for assigning value to the attributes of the newly created object. As you know from past labs, this has the disadvantage that you can forget to give value to an attribute and this would result in the creation of objects with inconsistent values. In order to solve this problem you must implement a constructor method to assign value to the attributes when an object is created. To do this, you have to pass a set of parameters to the constructor. This allows us to call the constructor as follows:

	new Album("Crazy Hits","Crazy Frog",2005,1,14.99,'D',false);
	

Solution

The solution is included in the following listing:

Album.java

public class Album { private String title; private String author; private int year; private int elements; private float price; private char genre; private boolean isSpanish; public Album(String title, String author, int year, int elements, float price, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setYear(int year) { this.year = year; } public void setElements(int elements) { this.elements = elements; } public void setPrice(float price) { this.price = price; } public void setGenre(char genre) { switch (genre) { case 'D': case 'P': case 'R': case 'C': case 'J': case 'O': this.genre = genre; break; default: System.out .println("The genre is not valid use one of the following characters: \n DANCE: D \n POP: P \n ROCK: R \n CLASSICAL: C \n JAZZ: J \n OTHER: O"); } } public void setIsSpanish(boolean isSpanish) { this.isSpanish = isSpanish; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } public int getElements() { return elements; } public float getPrice() { return price; } public char getGenre() { return genre; } public boolean getIsSpanish() { return isSpanish; } public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + price + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; // Object creation album1 = new Album("Crazy Hits", "Crazy Frog", 2005, 1, 14.99f, 'D', false); album2 = new Album("Cien gaviotas donde iran", "Varios", 2005, 1, 14.99f, 'O', true); // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); System.out.println("Total price (without IVA): " + (album1.getPrice() + album2.getPrice())); System.out.println("Total price (with 16% IVA): " + (1.16 * (album1.getPrice() + album2.getPrice()))); } }

Constants

Objective

Review the use of constants and the switch selection statement.

Exercise

Create constants to represent each different musical genre and assign its corresponding value, for instance, ROCK='R'. Modify the setGenre method so as to use these constants when the code checks the valid genres and assigns the value to the genre attribute.

Solution

The solution is included in the following listing:

Album.java

public class Album { public static final char DANCE = 'D'; public static final char POP = 'P'; public static final char ROCK = 'R'; public static final char CLASSICAL = 'C'; public static final char JAZZ = 'J'; public static final char OTHER = 'O'; private String title; private String author; private int year; private int elements; private float price; private char genre; private boolean isSpanish; public Album(String title, String author, int year, int elements, float price, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setYear(int year) { this.year = year; } public void setElements(int elements) { this.elements = elements; } public void setPrice(float price) { this.price = price; } public void setGenre(char genre) { switch (genre) { case DANCE: case POP: case ROCK: case CLASSICAL: case JAZZ: case OTHER: this.genre = genre; break; default: System.out .println("The genre is not valid use one of the following characters: \n DANCE: D \n POP: P \n ROCK: R \n CLASSICAL: C \n JAZZ: J \n OTHER: O"); } } public void setIsSpanish(boolean isSpanish) { this.isSpanish = isSpanish; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } public int getElements() { return elements; } public float getPrice() { return price; } public char getGenre() { return genre; } public boolean getIsSpanish() { return isSpanish; } public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + price + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

Reference types

Objective

Review the use of classes as reference types in attribute declaration.

Exercise

The album's price is something that could be changed depending on our pricing policies, seasonal offers, etc. We are going to change the price attribute in order to get a better management of these changes. Instead of using a basic type (double) we are going to create a new type called Rate. Thus we can declare a Rate class to encapsulate a set of data and specific behaviour that allows to calculate the album's price.

Implement a Rate class with the following information:

  • 3 constants to represent different prices (NORMAL=0, REDUCED=1, INCREASED=2)

  • A base attribute to represent the basic price without offers or surcharges

  • A plus attribute to represent the amount that will be added or subtracted to/from the basic price

  • A getPrice method that calculates the price using the following formula and returns its value:

    • Normal price = base*num

    • Reduced price (eg. seasonal offers) = base*num*(1-plus)

    • Increased price (eg. special edition) = base*num*(1+plus)

Solution

The solution is included in the following listing:

Album.java

public class Album { public static final char DANCE = 'D'; public static final char POP = 'P'; public static final char ROCK = 'R'; public static final char CLASSICAL = 'C'; public static final char JAZZ = 'J'; public static final char OTHER = 'O'; private String title; private String author; private int year; private int elements; private Rate rate; private char genre; private boolean isSpanish; public Album(String title, String author, int year, int elements, float price, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public Album(String title, String author, int year, int elements, float price, float plus, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price, plus); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public Album(String title, String author, int year, int elements, float price, float plus, int rateType, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price, plus, rateType); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setYear(int year) { this.year = year; } public void setElements(int elements) { this.elements = elements; } public void setPrice(float base) { rate = new Rate(base); } public void setPrice(float base, float plus) { rate = new Rate(base, plus); } public void setPrice(float base, float plus, int rateType) { rate = new Rate(base, plus, rateType); } public void setGenre(char genre) { switch (genre) { case DANCE: case POP: case ROCK: case CLASSICAL: case JAZZ: case OTHER: this.genre = genre; break; default: System.out .println("The genre is not valid use one of the following characters: \n DANCE: D \n POP: P \n ROCK: R \n CLASSICAL: C \n JAZZ: J \n OTHER: O"); } } public void setIsSpanish(boolean isSpanish) { this.isSpanish = isSpanish; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } public int getElements() { return elements; } public float getPrice() { float resultado = 0; resultado = (rate.getPrice()) * elements; return resultado; } public char getGenre() { return genre; } public boolean getIsSpanish() { return isSpanish; } public int getRateType() { int resultado = rate.getRateType(); return resultado; } public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + getPrice() + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println("Rate type:\t" + getRateType()); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; Album album3; // Object creation album1 = new Album("Crazy Hits", "Crazy Frog", 2005, 1, 14.99f, 0.1f, 1, 'D', false); album2 = new Album("Cien gaviotas donde iran", "Varios", 2005, 1, 14.99f, 0.1f, 2, 'O', true); album3 = new Album("Prueba", "Varios", 2005, 1, 14.99f, 0.1f, 0, 'O', true); // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); album3.printAlbum(); System.out.println("Total price (without IVA): " + (album1.getPrice() + album2.getPrice() + album3.getPrice())); System.out.println("Total price (with 16% IVA): " + (1.16 * (album1.getPrice() + album2.getPrice() + album3.getPrice()))); } }

Rate.java

public class Rate{ private static final int NORMAL = 0; private static final int REDUCED = 1; private static final int INCREASED = 2; private int rateType; private float base; private float plus; public Rate(float base){ this.base = base; this.plus = 10; setRateType(0); } public Rate(float base, float plus){ this.base = base; this.plus = plus; setRateType(0); } public Rate(float base, float plus, int rateType){ this.base = base; this.plus = plus; setRateType(rateType); } public void setRateType(int rateType){ if (rateType==NORMAL || rateType == REDUCED || rateType == INCREASED){ this.rateType=rateType; }else{ this.rateType=-1; System.out.println("The rate type is not valid use one of the following values: \n NORMAL: 0 \n REDUCED: 1 \n INCREASED: 2 \n "); } } public float getPrice(){ float resultado = 0; switch(rateType){ case NORMAL: resultado = base; break; case REDUCED: resultado = base*(1+plus); break; case INCREASED: resultado = base*(1-plus); break; } return resultado; } public int getRateType(){ return rateType; } }