Chapter 10

<< Chapter 9 | HomeworkTrailIndex | Chapter 11 >>

Inheritance

Demo 0: Name Tags

Make a super class Person with fields first and last and a methods nameTag which returns a String with the first and last name, getFirst, getLast, and a toString method

Make a subclass Student with an additional field grade and overload the nameTag method so it has only the first name and the grade.

Make a subclass Teacher with an additional field title and has its nameTag return the title and last name

iimport java.util.ArrayList;
public class NameTagDemo 
{
    public static void main(String[] args)
    {
        ArrayList<Person>folks=new ArrayList<Person>();
        folks.add(new Person("Miley", "Cyrus"));
        folks.add(new Student("Bob", "Smith", 9));
        folks.add(new Teacher("Mike", "Cannon", "Mr."));
        folks.add(new Student("Helen", "Brown", 11));
        folks.add(new Teacher("Dee", "Repetti", "Mrs."));
        System.out.println("Names:");
        for(Person attendee:folks)
            System.out.println(attendee);
        System.out.println("Name Tags:");
        for(Person attendee:folks)
            System.out.println(attendee.nameTag() );
        System.out.println("Classes:");
        for(Person attendee:folks)
        {
            if (attendee instanceof Person)
                  System.out.println(attendee.getFirst()+" is a Person" );
            if (attendee instanceof Student)
                  System.out.println(attendee.getFirst()+" is a Student" );
            if (attendee instanceof Teacher)
                  System.out.println(attendee.getFirst()+" is a Teacher" );
        }

    }
}

Demo 1: Shapes as subclasses of Polygon

Make the following shapes as subclasses of Polygon (use import java.awt*)

  1. Triangle
  2. Pentagon#
  3. Octagon
  4. Star

Hint for Octagon:

import java.awt.Polygon;
public class Octagon extends Polygon
{

    public Octagon(int x, int y, int radius){
        for(double theta=0; theta<2*Math.PI; theta+=2*Math.PI/8)
           addPoint((int)(radius*Math.cos(theta)), (int)(radius*Math.sin(theta)));
        translate(x+radius,y+radius);
    }
}

Tester

import java.awt.*;
import java.applet.Applet;
import java.util.ArrayList;
public class ShapeDemoTester extends Applet
{
    ArrayList<Polygon> shapes;
    public void init()
    {
       shapes=new ArrayList<Polygon>();
       shapes.add(new Octagon (20, 20, 50) );
       shapes.add(new Triangle (20, 200, 50) );
       shapes.add(new Pentagon (200, 20, 50) );
       shapes.add(new Star (200, 200, 50) );
    }


    public void paint(Graphics g)
    {
        // simple text displayed on applet
        g.setColor(Color.red);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.black);
        g.drawString("Octagon is a Polygon", 20, 20);
        g.drawString("Pentagon is a Polygon", 200, 20);
        g.drawString("Triangle is a Polygon", 20, 200);
        g.drawString("Star is a Polygon", 200, 200);
        g.setColor(Color.blue);

        for (Polygon theShape:shapes)
             g.fillPolygon(theShape);
    }

}

Demo2:Accounts

BankAccount.java

/**
   A bank account has a balance that can be changed by 
   deposits and withdrawals.
*/
public class BankAccount
{  
    private double balance; 
  /**
      Constructs a bank account with a zero balance.
   */
   public BankAccount()
   {  
      balance = 0;
   }

   /**
      Constructs a bank account with a given balance.
      @param initialBalance the initial balance
   */
   public BankAccount(double initialBalance)
   {  
      balance = initialBalance;
   }

   /**
      Deposits money into the bank account.
      @param amount the amount to deposit
   */
   public void deposit(double amount) 
   {  
      balance = balance + amount;
   }

   /**
      Withdraws money from the bank account.
      @param amount the amount to withdraw
   */
   public void withdraw(double amount) 
   {  
      balance = balance - amount;
   }

   /**
      Gets the current balance of the bank account.
      @return the current balance
   */
   public double getBalance()
   {  
      return balance; 
   }

   /**
      Transfers money from the bank account to another account
      @param amount the amount to transfer
      @param other the other account
   */
   public void transfer(double amount, BankAccount other)
   {  
      withdraw(amount);
      other.deposit(amount);
   }


}

SavingsAccount.java

/**
   An account that earns interest at a fixed rate.
*/
public class SavingsAccount extends BankAccount
{  
   private double interestRate;   
   /**
      Constructs a bank account with a given interest rate.
      @param rate the interest rate
   */
   public SavingsAccount(double rate) 
   {  
      interestRate = rate;
   }

   /**
      Adds the earned interest to the account balance.
   */
   public void addInterest() 
   {  
      double interest = getBalance() * interestRate / 100;
      deposit(interest); 
   }

}

CheckingAccount.java

/**
   A checking account that charges transaction fees.
*/
public class CheckingAccount extends BankAccount
{  
   private int transactionCount;
   private static final int FREE_TRANSACTIONS = 3;
   private static final double TRANSACTION_FEE = 2.0;
   /**
      Constructs a checking account with a given balance.
      @param initialBalance the initial balance
   */
   public CheckingAccount(double initialBalance)
   {  
      // Construct superclass
      super(initialBalance);

      // Initialize transaction count
      transactionCount = 0; 
   }

   public void deposit(double amount) 
   {  
      transactionCount++;
      // Now add amount to balance 
      super.deposit(amount); 
   }

   public void withdraw(double amount) 
   {  
      transactionCount++;
      // Now subtract amount from balance 
      super.withdraw(amount); 
   }

   /**
      Deducts the accumulated fees and resets the
      transaction count.
   */
   public void deductFees()
   {  
      if (transactionCount > FREE_TRANSACTIONS)
      {  
         double fees = TRANSACTION_FEE *
               (transactionCount - FREE_TRANSACTIONS);
         super.withdraw(fees);
      }
      transactionCount = 0;
   }

}

AccountTester.java

/**
   This program tests the BankAccount class and
   its subclasses. 
*/
public class AccountTester
{  
   public static void main(String[] args)
   {  
      SavingsAccount momsSavings 
            = new SavingsAccount(0.5);

      CheckingAccount harrysChecking
            = new CheckingAccount(100);

      momsSavings.deposit(10000);

      momsSavings.transfer(2000, harrysChecking);     
      harrysChecking.withdraw(1500);
      harrysChecking.withdraw(80);      

      momsSavings.transfer(1000, harrysChecking);
      harrysChecking.withdraw(400);      

      // Simulate end of month
      momsSavings.addInterest();
      harrysChecking.deductFees();

      System.out.println("Mom's savings balance: "
            + momsSavings.getBalance());
      System.out.println("Expected: 7035");

      System.out.println("Harry's checking balance: "
            + harrysChecking.getBalance());
      System.out.println("Expected: 1116");
   }
}

Demo3:Viewing the Accounts

InvestmentFrame.java

public class InvestmentFrame extends JFrame
{
   public InvestmentFrame()
   {
      account = new BankAccount(INITIAL_BALANCE);

      // Use instance fields for components
      label = new JLabel(''balance: '' + account.getBalance());

      // Use helper methods
      createButton();
      createPanel();
      setSize(FRAME_WIDTH, FRAME_HEIGHT);
   }
   private void createButton()
   {
      ActionListener listener = new AddInterestListener();
      button.addActionListener(listener);
      button = new JButton(''Add Interest'');
   }
   private void createPanel()
   {
      panel = new JPanel();
      panel.add(button);
      panel .add(label);
      add(panel);
   }
   private JButton button;
   private JLabel label;
   private JPanel panel;
   private BankAccount account;
}

InvestmentViewer2.java

public class InvestmentViewer2
{
   public static void main(String[] args)
   {
      JFrame frame = new InvestmentFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
   }
}

Demo4:Text Input from a GUI

InvestmentFrame.java (text Input version)

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

/**
   A frame that shows the growth of an investment with variable interest.
*/
public class InvestmentFrame extends JFrame
{

   private JLabel rateLabel;
   private JTextField rateField;
   private JButton button;
   private JLabel resultLabel;
   private JPanel panel;
   private BankAccount account;

   private static final int FRAME_WIDTH = 450;
   private static final int FRAME_HEIGHT = 100;

   private static final double DEFAULT_RATE = 5;
   private static final double INITIAL_BALANCE = 1000;   
   public InvestmentFrame()
   {  
      account = new BankAccount(INITIAL_BALANCE);

      // Use instance fields for components 
      resultLabel = new JLabel("balance: " + account.getBalance());

      // Use helper methods 
      createTextField();
      createButton();
      createPanel();

      setSize(FRAME_WIDTH, FRAME_HEIGHT);
   }

   private void createTextField()
   {
      rateLabel = new JLabel("Interest Rate: ");

      final int FIELD_WIDTH = 10;
      rateField = new JTextField(FIELD_WIDTH);
      rateField.setText("" + DEFAULT_RATE);
   }

   private void createButton()
   {
      button = new JButton("Add Interest");

      class AddInterestListener implements ActionListener
      {
         public void actionPerformed(ActionEvent event)
         {
            double rate = Double.parseDouble(
                  rateField.getText());
            double interest = account.getBalance() 
                  * rate / 100;
            account.deposit(interest);
            resultLabel.setText(
                  "balance: " + account.getBalance());
         }            
      }

      ActionListener listener = new AddInterestListener();
      button.addActionListener(listener);
   }

   private void createPanel()
   {
      panel = new JPanel();
      panel.add(rateLabel);
      panel.add(rateField);
      panel.add(button);
      panel.add(resultLabel);      
      add(panel);
   }

}

InvestmentFrame.java (text are version)

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
   A frame that shows the growth of an investment with variable interest.
*/
public class InvestmentFrame extends JFrame
{

   private JLabel rateLabel;
   private JTextField rateField;
   private JButton button;
   private JTextArea resultArea;
   private JPanel panel;
   private BankAccount account;

   private static final int FRAME_WIDTH = 400;
   private static final int FRAME_HEIGHT = 250;

   private static final int AREA_ROWS = 10;
   private static final int AREA_COLUMNS = 30;

   private static final double DEFAULT_RATE = 5;
   private static final double INITIAL_BALANCE = 1000;   

   public InvestmentFrame()
   {  
      account = new BankAccount(INITIAL_BALANCE);
      resultArea = new JTextArea(AREA_ROWS, AREA_COLUMNS);
      resultArea.setEditable(false);

      // Use helper methods 
      createTextField();
      createButton();
      createPanel();

      setSize(FRAME_WIDTH, FRAME_HEIGHT);
   }

   private void createTextField()
   {
      rateLabel = new JLabel("Interest Rate: ");

      final int FIELD_WIDTH = 10;
      rateField = new JTextField(FIELD_WIDTH);
      rateField.setText("" + DEFAULT_RATE);
   }

   private void createButton()
   {
      button = new JButton("Add Interest");

      class AddInterestListener implements ActionListener
      {
         public void actionPerformed(ActionEvent event)
         {
            double rate = Double.parseDouble(
                  rateField.getText());
            double interest = account.getBalance() 
                  * rate / 100;
            account.deposit(interest);
            resultArea.append(account.getBalance() + "\n");
         }            
      }

      ActionListener listener = new AddInterestListener();
      button.addActionListener(listener);
   }

   private void createPanel()
   {
      panel = new JPanel();
      panel.add(rateLabel);
      panel.add(rateField);
      panel.add(button);
      JScrollPane scrollPane = new JScrollPane(resultArea);
      panel.add(scrollPane);      
      add(panel);
   }

}

Demo 5:CoinPurse Using the Gridworld Case Study

Coin and PurseWorld


Review Exercises

R10.4. Identify the superclass and the subclass in each of the following pairs of classes.

(a) Employee, Manager

(b) Polygon, Triangle

(c) GraduateStudent, Student

(d) Person, Student

(e) Employee, GraduateStudent

(f) BankAccount, CheckingAccount

(g) Vehicle, Car

(h) Vehicle, Minivan

(i) Car, Minivan

(j) Truck, Vehicle

R10.5. Suppose the class Sub extends the class Sandwich. Which of the following assignments are legal?

 Sandwich x = new Sandwich();
Sub y = new Sub();

(a) x = y;

(b) y = x;

(c) y = new Sandwich();

(d) x = new Sub()

R10.9. Which of these conditions returns true? Check the Java documentation for the inheritance patterns.

(a) Rectangle r = new Rectangle(5, 10, 20, 30);

(b) if (r instanceof Rectangle) …

(c) if (r instanceof Point) …

(d) if (r instanceof Rectangle2D.Double) …

(e) if (r instanceof RectangularShape) …

(f) if (r instanceof Object) …

(g) if (r instanceof Shape) …

R10.17. Why are public fields dangerous? Are public static fields more dangerous than public instance fields?

R10.18. What is the difference between a label, a text field, and a text area?


Programming Exercises, 10.3 for 8 points, both 10.3 and 10.5 for 9 points, 10.3, 10.5 and 10.16 for 10 points and all four for 11 points.

P10.3. Implement a subclass Square that extends the Rectangle class. In the constructor, accept the x- and y-positions of the center and the side length of the square. Call the setLocation and setSize methods of the Rectangle class. Look up these methods in the documentation for the Rectangle class. Also supply a method getArea that computes and returns the area of the square. Write a sample program that asks for the center and side length, then prints out the square (using the toString method that you inherit from Rectangle) and the area of the square.

You need to supply the Square class.

Use the following class as your tester class:

/**
   This class tests the Square class.
*/
public class SquareTester
{
   public static void main(String[] args)
   {
      Square sq = new Square(10, 20, 30);
      System.out.println(sq.toString());
      System.out.println("Expected: Square[x=-5,y=5,width=30,height=30]");
      System.out.println("Area: " + sq.getArea());
      System.out.println("Expected: 900");
   }
}

P10.5. Make a class Employee with a name and salary. Make a class Manager inherit from Employee. Add an instance field, named department, of type String. Supply a method toString that prints the manager's name, department, and salary. Make a class Executive inherit from Manager. Supply appropriate toString methods for all classes. Supply a test program that tests these classes and methods.

Use the following class as your tester class:

/**
   This program tests the Employee class and its subclasses.
*/
public class EmployeeTester
{
   public static void main(String[] args)
   {
      Employee e = new Employee("Edgar", 65000);
      Manager m = new Manager("Mary", 85000, "Engineering");
      Executive v = new Executive("Veronica", 105000, "Engineering");
      System.out.println(e);
      System.out.println("Expected: Employee[name=Edgar,salary=65000.0]");
      System.out.println(m);
      System.out.println("Expected: Manager[super=Employee[
            name=Mary,salary=85000.0],department=Engineering]");
      System.out.println(v);
      System.out.println("Expected: Executive[super=Manager[
            super=Employee[name=Veronica,salary=105000.0],
            department=Engineering]]");
   }
}

P10.16. Write a program that prompts the user to enter the x- and y-positions of the center and a radius. When the user clicks a “Draw” button, draw a circle with that center and radius in a component.

Use the following class as your main class:

import javax.swing.JFrame;
/**
   Prompts the user to enter the x- and y-positions of the center and a radius.
   When the user clicks a ''Draw'' button, draw a circle with that center and
   radius in a component.
/*
public class CircleDrawer
{
   public static void main(String[] args)
   {
      JFrame frame = new CircleDrawerFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle(''CircleDrawer'');
      frame.setVisible(true);
   }
}

Use the following class in your solution:

import javax.swing.JComponent;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
/**
   Displays a circle at a given position.
*/
public class CircleDrawerComponent extends JComponent
{
   public CircleDrawerComponent()
   {
      x = 0;
      y = 0;
      radius = 0;
      circle = null;
   }
   public void setPositionAndSize(int aX, int aY, int aRadius)
   {
      x = aX;
      y = aY;
      radius = aRadius;

      // the circle that the pai ntComponent method draws
      circle = new Ellipse2D.Double(
            x - radius, y - radius, radius * 2, radius * 2);
      repaint();
   }
   public void paintComponent(Graphics g)
   {
      if (circle == null) return;
      Graphics2D g2 = (Graphics2D) g;
      g2.draw(circle);
   }
   private Ellipse2D.Double circle;
   private int x;
   private int y;
   private int radius;
}

CircleDrawerComponent.java

import javax.swing.JComponent;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;

/**
   Displays a circle at a given position.
*/
public class CircleDrawerComponent extends JComponent
{ 
   public CircleDrawerComponent()
   {  
      x = 0;
      y = 0;
      radius = 0;
      circle = null;
   }

   public void setPositionAndSize(int aX, int aY, int aRadius)
   {

      ///YOUR CODE HERE

      repaint();
   }

   public void paintComponent(Graphics g)
   {
      if (circle == null) return;
      Graphics2D g2 = (Graphics2D) g;      
      g2.draw(circle);
   }

   private Ellipse2D.Double circle;
   private int x;
   private int y;
   private int radius;
}

CircleDrawerFrame.java

import javax.swing.JFrame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.Dimension;

/**
   Prompts the user to enter the x- and y-positions of the center and a radius.
   When the user clicks a "Draw" button, draw a circle with that center and
   radius in a component.
 */
public class CircleDrawerFrame extends JFrame
{  
   public CircleDrawerFrame()
   {
      component = new CircleDrawerComponent();
      component.setPreferredSize(new Dimension(400,350));

      // the text fields
      xField = new JTextField(5);
      yField = new JTextField(5);
      rField = new JTextField(5);

      // the labels for labeling the text fields
      JLabel xLabel = new JLabel("x: ");
      JLabel yLabel = new JLabel("y: ");
      JLabel rLabel = new JLabel("radius: ");

      // the panel for holding the user interface components
      JPanel panel = new JPanel();

      panel.add(xLabel);
      panel.add(xField);
      panel.add(yLabel);
      panel.add(yField);
      panel.add(rLabel);
      panel.add(rField);
      panel.add(createDrawButton());
      panel.add(component);

      setSize(FRAME_WIDTH, FRAME_HEIGHT);
      add(panel);
   }

   private JButton createDrawButton()
   {
      // the button to draw the circle
      JButton drawButton = new JButton("Draw");    

      class DrawButtonListener implements ActionListener
      {
         public void actionPerformed(ActionEvent event)
         {
            int x = Integer.parseInt(xField.getText());
            int y = Integer.parseInt(yField.getText());
            int radius = Integer.parseInt(rField.getText());

            component.setPositionAndSize(x, y, radius);

            // clears the text fields
            xField.setText("");
            yField.setText("");
            rField.setText("");
         }
      }

      ActionListener listener = new DrawButtonListener();
      drawButton.addActionListener(listener);      

      return drawButton;
   }

   private JTextField xField;
   private JTextField yField;
   private JTextField rField;
   private CircleDrawerComponent component;

   private static final int FRAME_WIDTH = 400;
   private static final int FRAME_HEIGHT = 400;
}

P10.19. Write a program that draws a clock face with a time that the user enters in two text fields (one for the hours, one for the minutes).

Hint: You need to determine the angles of the hour hand and the minute hand. The angle of the minute hand is easy: The minute hand travels 360 degrees in 60 minutes. The angle of the hour hand is harder; it travels 360 degrees in 12 × 60 minutes.

Use the following class as your main class:

import javax.swing.JFrame;
/**
   This program displays a clock face with a time that the user specified.
*/
public class ClockViewer
{
   public static void main(String[] args)
   {
      JFrame frame = new ClockViewerFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle(''ClockViewer'');
      frame.setVisible(true);
   }
}