8. Inheritance

About this Tutorial –

Objectives –

This course is aimed at object-oriented developers (e.g. C++ or C#) who need to transition into Java. It is also aimed at those learning to program for the first time; the course covers the Java programming constructs and APIs quickly, focussing on the differences between Java and other OO languages.

Audience

This training course is aimed at OO developers who need to transition into Java.

Prerequisites

No previous experience in Java programming is required. But any experience you do have in programming will help. Also no experience in eclipse is required. But again any experience you do have with programming development environments will be a valuable.

Contents

The Java course cover these topics and more:

  • Flow Control: Decision making: if and if-else; The switch statement; Looping: for loops; while loops; do-while loops; for-each style loops; Assertionsv
  • Concurrency: Overview of multithreading; Creating new threads; Object locking; Using wait, notify, and notifyAll
  • Collections: Overview of Java SE collection classes; Generics; Using List-based collection classes; Using Set-based collection classes; Using Map-based collection classes; Collection techniques

Exam Preparation

The Java course will help you prepare for these certifications:

  • Oracle Certified Java Associate – Exam 1Z0-803
  • Oracle Certified Java Professional – Exam 1Z0-804

Download Solutions

HTML tutorial


Overview

Estimated Time – 2 Hours

Not what you are looking? Try the next tutorial – Interfaces

Lab 1: Overview of inheritance

Lab 1: Overview of inheritance
  1. Inheritance and OO
    • Inheritance is a very important part of object-oriented development
      • Allows you to define a new class based on an existing class
      • You just specify how the new class differs from the existing class
    • Terminology:
      • For the “existing class”: Base class, superclass, parent class
      • For the “new class”: Derived class, subclass, child class
    • Potential benefits of inheritance:
      • Improved OO model
      • Faster development
      • Smaller code base
  2. Superclasses and Subclasses
    • The subclass inherits everything from the superclass (except constructors)
      • You can define additional variables and methods
      • You can override existing methods from the superclass
      • You typically have to define constructors too
      • Note: You can’t cherry pick or “blank off” superclass members
  3. Inheritance in Java
    • Java supports single inheritance
      • All classes have one direct superclass (i.e. Java does not support multiple inheritance of classes)
      • Everything ultimately inherits from java.lang.Object
    • Here’s a tiny snippet of the standard Java inheritance hierarchy
    • T8P1

  4. The Object Class
    • The Object class defines methods that are available to all types in Java
      • clone() – Creates and returns a copy of object (object must implement Cloneable)
      • equals() – Indicates whether some other object is “equal to” this one
      • finalize() – Called automatically on object when it is being garbage collected
      • getClass() – Returns a Class object that provides run-time information about this object
      • hashCode() – Returns a hash code value for object
      • notify(), notifyAll(), wait() – ociated with multithreading (see later in the course)
      • toString() – Returns string representation of object (default returns classname@hashcode)
Lab
  1. Getting started with the library system
    • In the student project, take a look at the pre-written Member class, which represents a member in a library
    • The Member class has the following members:
      • Instance variables containing the member’s name and age, plus an integer indicating how many items the member has currently borrowed
         // Instance variables.
         private String name;
         private int age;
         private int numberItemsBorrowed = 0;
      • View code file.
      • A constructor, which initializes the instance variables
         // Constructor.
         public Member(String name, int age) {
          this.name = name;
          this.age = age;
         }
      • View code file.
      • A toString() method, which returns a textual representation of the member’s details
         // String representation.
         @Override
         public String toString() {
          return String.format("%s, aged %d, has %d items(s) on loan.", name, age, numberItemsBorrowed);
         }
      • View code file.
      • Methods named borrowedItem() and returnedItem(), which increment and decrement the “items borrowed” count respectively (you’ll call these methods whenever an item is borrowed or returned by the member)
         // Business methods.
         public void borrowedItem() {
          numberItemsBorrowed++;
         }
         public void returnedItem() {
          numberItemsBorrowed--;
         }
        }
      • View code file.

Lab 2: Defining superclasses and subclasses

Lab 2: Defining superclasses and subclasses
  1. Sample Hierarchy
    • We’ll see how to implement the following hierarchy in this chapter:
    • T8P2

    • Note:
      • BankAccount defines common state and behaviour that is relevant for all kinds of account
      • SavingsAccount “is a kind of” BankAccount that earns interest
      • CurrentAccount “is a kind of” BankAccount that has cheques
  2. Superclass Considerations
    • To define a superclass, just define a regular class
      • Although there are some issues you need to consider
    • You can allow subclasses special access to your members
      • Designate members as “protected” (see later in this section)
    • You can stop clients from creating instances of your class
      • Designate the class as “abstract” (see later in this chapter)
    • You can defer a method implementation to subclasses
      • Designate the method as “abstract” (see later in this chapter)
    • You can stop anyone from extending your class, or from overriding methods
      • Designate the class or methods as “final” (see later in this chapter)
  3. Access Modifiers
    • Java supports 4 access levels for members in a class
    • public
      • Accessible by anyone
      • Methods and constants are often public
    • private
      • Accessible only by class itself
      • Data and helper methods are usually private
    • protected
      • Accessible by class itself, subclasses, and classes in same package
      • Allow access to members that are hidden from general client code
    • (No access modifier)
      • Accessible by class itself, and classes in same package
  4. Defining a Superclass
    • Here are the interesting parts of the BankAccount class
      • This is a simplification for now:
        public class BankAccount {
         // Instance data.
         private String accountHolder;
         private int id;
         protected double balance = 0.0;
         private Date creationTimestamp = new Date();
         // Class data ....
         // Constructors ...
         // Instance methods ...
         // Class methods ...
        }
      • View code file.
    • Note:
      • balance is protected, so it can be accessed by subclasses
      • All instance methods in Java are inherently “overridable” (unless marked as final – see later in this chapter)
  5. Defining a Subclass
    • To define a subclass, use the extends keyword
      • Remember, a Java class can only inherit from one direct superclass
        public class SavingsAccount extends BankAccount {
         // Additional data and methods ...
         // Constructor(s) ...
         // Overrides for superclass methods, if necessary ...
        }
      • View code file.
  6. Adding New Members
    • The subclass inherits everything from the superclass
      • (Except for constructors)
      • The subclass can define additional members if it needs to; such as new additional vars and new additional methods
        public class SavingsAccount extends BankAccount {
         private boolean premium;
         private boolean goneOverdrawn;
         private static final double BASIC_INTEREST_RATE  = 0.015;
         ...
         public void applyInterest() {
          if (balance < 0) {    // Sorry mate, no interest if you're overdrawn.   }   else if (premium && !goneOverdrawn) {    balance *= (1 + PREMIUM_INTEREST_RATE);   }   else {    balance *= (1 + BASIC_INTEREST_RATE);   }   goneOverdrawn = false;  }  ... }
      • View code file.
  7. Defining Constructors
    • The subclass doesn't inherit constructors from superclass
      • So, define constructor(s) in subclass, to initialize subclass data
    • The subclass constructor must invoke the superclass constructor, to initialize superclass data
      • To do this, call super(params) as the first statement in the subclass constructor
        public class SavingsAccount extends BankAccount {
         ...
         public SavingsAccount(String accountHolder, boolean premium) {
          super(accountHolder);
          this.premium = premium;
         }
         ...
        }
      • View code file.
  8. Overriding Methods
    • The subclass can override superclass instance methods
      • To provide a different (or supplementary) implementation
      • No obligation
    • If you do decide to override a method in a subclass:
      • The signature must match the superclass method signature
      • The return type must be the same (or a subclass, this is called a "covariant" return)
      • The access level must be the same (or less restrictive)
      • The list of checked exception must be narrower or fewer (it can't be broader or new checked exception)
    • An override can call the original superclass method, to leverage existing functionality
      • Via super.methodName(params)
    • Examples of overriding methods:
    • T8P3

Lab
  1. Defining a base class
    • Define an Item class, which will be the base class for all the different types of item in the library. Item should be an abstract class - why?
    • The Item class should have the following instance variables:
      • Title (a String, initialized in a constructor)
      • Date borrowed (a Date, null initially to indicate it's not borrowed yet)
      • Current borrower (a reference to a Member object, null initially).
         // Instance variables.
         private String title;
         protected Date dateBorrowed = null;
         private Member borrower = null;
      • View code file.
    • The Item class should have the following instance methods:
      • isBorrowed() - Returns a boolean to indicate whether the item is currently borrowed (test the "current borrower" field to see if it's null)
         public boolean isBorrowed() {
          return borrower != null;
         }
      • View code file.
      • canBeBorrowedBy() - Takes a Member object as a parameter, and returns a boolean to indicate whether this member is allowed to borrow this item. Returns true by default (subclasses might override this method, with different rules for whether a member can borrow specific types of item
         public boolean canBeBorrowedBy(Member member) {
          return true;
         }
      • View code file.
      • borrowItemBy() - Takes a Member object as a parameter, and returns a boolean to indicate whether the borrow succeeded. The implementation of this method should follow these guidelines:
        • The fundamental rule is that an item can't be borrowed if someone has already borrowed it!
            // Has the item not been borrowed yet, and is the specified member allowed to borrow it?
            if (!isBorrowed() && canBeBorrowedBy(member)) {
            ...
            } else {
             return false;
            }
        • View code file.
        • There are additional constraints on who can borrow what, as defined by the canBeBorrowedBy() method, so invoke this method. If the method returns true, set the item's instance variables to record the borrower and the date borrowed. Also, invoke borrowedItem() on the Member object, to increment the number of items borrowed by this member
             // Record the fact that this item is now borrowed by the member.
             borrower = member;
             dateBorrowed = new Date();
             borrower.borrowedItem();
             return true;
        • View code file.
        • Return true or false, to indicate whether the borrowing succeeded
      • returnItem() - Takes no parameters, and returns void. The implementation of this method should follow these guidelines:
        • Call returnedItem() on the item's borrower, to decrement the number of items borrowed by that member
            // Record the fact that this item is no longer borrowed by the member.
            borrower.returnedItem();
        • View code file.
        • Set the item's instance variables to record the fact that the item is no longer borrowed
            borrower = null;
            dateBorrowed = null;
        • View code file.
      • toString() - Returns a textual representation of the item's details, indicating whether the item is currently on loan (and to whom)
         // String representation.
         @Override
         public String toString() {
          
          if (borrower != null) {
           return String.format("%s is on loan to %s [borrowed at %tc].", title, borrower.getName(), dateBorrowed);
          } else {
           return String.format("%s is not on loan.", title);
          }
         }
      • View code file.

Lab 3: Polymorphism

Lab 3: Polymorphism
  1. What is Polymorphism?
    • Greek for "many forms"
    • In an OO context:
      • You can have many different "kinds" of object (e.g. many different kinds of bank accounts)
      • Your application can treat them all in the same way
      • Your application doesn't need to know which particular kind of object it's using at any given moment
  2. The Principle of Substitutability
    • Polymorphism is facilitated by the principle of substitutability
      • A superclass reference can refer to any kind of subclass object e.g. "ca" and "sa" in the code below
        public static void demoPolymorphism() {
         BankAccount sa = new SavingsAccount("Mickey", true);
         BankAccount ca = new CurrentAccount("Donald", 50);
         processAccount(sa);
         processAccount(ca);
        }
        public static void processAccount(BankAccount account) {
         ...
        }
  3. Polymorphism in Action
    • Question:
      • What happens when you invoke an instance method via a superclass reference?
    • Answer:
      • The "correct" version of the method is invoked, depending on the actual type of object currently pointed to
    • Specifically, this is what polymorphism boils down to:
      • If the reference actually points to a subclass object -
      • And that subclass has overridden the method
      • The subclass's version of the method is called
        public static void processAccount(BankAccount account) {
         account.withdraw(200);
         account.deposit(300);
         System.out.println(account.toString());
        }
  4. Accessing Subclass-Specific Members
    • Polymorphism is great
      • You can write general-purpose code that doesn't care what actual subclass objects it's dealing with
      • The downside is that you can't actually access subclass-specific members via a superclass reference
    • If you really need to access subclass-specific members:
      • Use instanceof to determine if the reference points to a particular subclass object type
      • Then cast the reference to that subclass type
        public static void processAccount(BankAccount account) {
         ...
         if (account instanceof SavingsAccount) {
          SavingsAccount temp = (SavingsAccount)account;
          temp.applyInterest();
         }
         ...
        }
  5. Polymorphic Collections
    • A polymorphic collection (or array) can hold different types of subclass objects
      • Achieved by specifying the superclass as the generic type parameter (or as the array type)
    • Allows you to insert any type of subclass object into the collection/array
      • When you access items in the collection/array, you are working with superclass references
        List accounts = new ArrayList();
        accounts.add(new SavingsAccount("Pluto", true));
        accounts.add(new CurrentAccount("Goofy", 50));
        ...
        for (BankAccount account: accounts) {
         processAccount(account);
        }
Lab
  1. Defining subclasses
    • Define Book and DVD classes, which inherit from the Item base class
    • The Book class should have the following additional members, to extend the capabilities of the Item base class:
      • Instance variables for the book's author, ISBN, and genre. Implement the genre as an enum (allowable options are Children, Fiction, NonFiction)
        // Books have a genre, of the following type:
        enum Genre {
         Children,
         Fiction,
         NonFiction
        }
         // Instance variables.
         private String author;
         private String isbn;
         private Genre genre;
      • View code file.
      • Suitable constructor(s)
         // Constructor.
         public Book(String title, String author, String isbn, Genre genre) {
          super(title);
          this.author = author;
          this.isbn = isbn;
          this.genre = genre;
         }
      • View code file.
      • An override for the canBeBorrowedBy() method. The policy for books is that any member can borrow fiction and non-fiction books, but only children (age <= 16) can borrow children's books
         @Override
         public boolean canBeBorrowedBy(Member member) {
          
          if (genre == Genre.Children) {
           // Children's books can only be borrowed by children.
           return member.getAge() <= 16;   } else {    // Other books can be borrowed by anyone.    return true;   }  }
      • View code file.
      • An override for toString(), to return a textual representation of a book (including all the basic information in the Item base class, of course)
         @Override
         public String toString() {
          return String.format("%s\n Additional book details: %s %s %s.", super.toString(), author, isbn, genre);
         }
         // Implementations of abstract methods.
         public Date dateDueBack() {
          if (dateBorrowed == null) {
           return null;
          } else {
           Calendar cal = new GregorianCalendar();
           cal.setTime(dateBorrowed);
           cal.add(Calendar.DATE, 21);
           return cal.getTime();
          }
         }
      • View code file.
    • The DVD class should have the following additional members, to extend the capabilities of the Item base class:
      • Instance variables for the DVD playing time (in minutes) and classification. Implement the classification as an enum (allowable options are Universal, Youth, Adult)
        // DVDs have a classification, of the following type:
        enum Classification {
         Universal,
         Youth,
         Adult
        }
         // Instance variables.
         private int playingTime;
         private Classification classification;
      • View code file.
      • Suitable constructor(s)
         // Constructor.
         public DVD(String title, int playingTime, Classification classification) {
          super(title);
          this.playingTime = playingTime;
          this.classification = classification;
         }
      • View code file.
      • An override for the canBeBorrowedBy() method. "Universal" DVDs can be borrowed by anyone; "youth" DVDs can be borrowed by anyone 12 or over; and "adult" DVDs can be borrowed by anyone 18 or over
         @Override
         public boolean canBeBorrowedBy(Member member) {
          if (classification == Classification.Universal) {
           // Universal DVDs can be borrowed by anyone.
           return true;
          } else if (classification == Classification.Youth) {
           // Youth DVDs can be borrowed by anyone aged 12 or above.
           return member.getAge() >= 12;
          } else {
           // Adult DVDs can be borrowed by anyone aged 18 or above.
           return member.getAge() >= 18;
          }
         }
      • View code file.
      • An override for toString(), to return a textual representation of a DVD (including all the basic information in the Item base class)
         public String toString() {
          return String.format("%s\n Additional DVD details: %d %s.", super.toString(), playingTime, classification);
         }
         // Implementations of abstract methods.
         public Date dateDueBack() {
          if (dateBorrowed == null) {
           return null;
          } else {
           Calendar cal = new GregorianCalendar();
           cal.setTime(dateBorrowed);
           cal.add(Calendar.DATE, 7);
           return cal.getTime();
          }
         }
      • View code file.

Lab 4: Additional techniques

Lab 4: Additional techniques
  1. abstract Classes
    • When you define an inheritance hierarchy, you often find that the superclass is "incomplete"
      • It contains common members for its subclasses, but it doesn't have enough know-how to represent a real object
    • In such cases, declare the superclass as abstract
      • The compiler will prevent any instances of the superclass ever being created
        public abstract class BankAccount {
         ...
        }
      • View code file.
  2. abstract Methods
    • When you define an inheritance hierarchy, the superclass must list all the methods that will be available to the client
      • The problem is, the superclass might not know how to actually implement some of these methods
      • For example, the implementation details might vary completely across all the subclasses
    • In such cases, declare the method as abstract
      • The superclass does not provide a method body
      • Instead, each subclass is obliged to implement the method
        public abstract class BankAccount {
         ...
         public abstract String getTermsAndConditions();
         public abstract double getGuaranteedLimit();
        }
        public class SavingsAccount extends BankAccount {
         ...
         public String getTermsAndConditions() { ...}
         public double getGuaranteedLimit() { ...}
        }
      • View code file.
  3. final Classes
    • If you want to prevent any further classes from extending your class:
      • Define it as a final class
      • This is very bold step -
        public final class SavingsAccount extends BankAccount {
         ...
        }
      • View code file.
  4. final Methods
    • If you want to prevent any subclass from overriding a particular method:
      • Define it as a final method
      • Disables polymorphism on that method
      • Why might this be a useful thing to do?
        public abstract class BankAccount {
         ...
         public final int getId() {
          return id;
         }
         public final double getBalance() {
          return balance;
         }
         public final Date getCreationTimestamp() {
          return creationTimestamp;
         }
         ...
        }
      • View code file.
Lab
  1. Writing the client application
    • In MainProgram.java, write a main() method to test the classes in your hierarchy
    • Suggestions and requirements:
      • First, create some Member objects with various names and ages
          // Create some members.
          Member[] members = new Member[3];
          members[0] = new Member("Ben", 10);
          members[1] = new Member("Zak", 15);
          members[2] = new Member("Joe", 30);
      • View code file.
      • Then declare an Item[] array variable, which is capable of holding any "kind of item"
          // Create an array to hold all items.
          Item[] items = new Item[6];
      • View code file.
      • Create some Book and DVD objects and place them in the array
          // Create some books.
          items[0] = new Book("Great Expectations", "Charles Dickens", "978-0141439563", Genre.Fiction);
          items[1] = new Book("The First Moon Landing", "Gillian Clements", "978-0749649333", Genre.NonFiction);
          items[2] = new Book("The Griffalo", "Julia Donaldson", "B001TIBX3K", Genre.Children);
          // Create some DVDs.
          items[3] = new DVD("Shrek 3", 90, Classification.Universal);
          items[4] = new DVD("The Bourne Ultimatum", 100, Classification.Youth);
          items[5] = new DVD("The Sopranos", 420, Classification.Adult);
      • View code file.
      • Borrow some books and DVDs. Test the rules that govern whether a member is allowed to borrow a book
          // See if a member can borrow many items.
          items[0].borrowItemBy(members[0]);
          items[3].borrowItemBy(members[0]);
          System.out.println("member[0]: " + members[0]);
          System.out.println("\nitem[0]: " + items[0]);
          System.out.println(" Due back: " + items[0].dateDueBack());
          System.out.println("\nitem[3]: " + items[3]);
          System.out.println(" Due back: " + items[3].dateDueBack());
          // Make sure an item can't be borrowed if it's already on loan.
          boolean result = items[0].borrowItemBy(members[1]);
          System.out.println("\nCould member borrow item that was already on loan? " + result);
          // Return items.
          items[0].returnItem();
          items[3].returnItem();
      • View code file.
      • What happens if a member attempts to borrow an item that is already borrowed by someone else? Clearly this shouldn't be allowed, but does your application enforce this rule? Where would you write the code to make this test?
      • Write a loop to iterate through all the items and display each one. Verify that the correct toString() method is called on each item, thanks to polymorphism.
          // Try to borrow each item by each member (and return it immediately).
          for (Item item : items) {
           
           for (Member member : members) {
            
            if (item.borrowItemBy(member)) {
             System.out.printf("\nSuccessful borrow!\n %s\n %s\n", item, member);
             item.returnItem();
            } else {
             System.out.printf("\nUnsuccessful attempt to borrow!\n %s\n %s\n", item, member);
            }
           }
          }
      • View code file.

 

Well done. You have completed the tutorial in the Java course. The next tutorial is

9. Interfaces


Back to beginning
Copyright © 2016 TalkIT®






If you liked this post, please comment with your suggestions to help others.
If you would like to see more content like this in the future, please fill-in our quick survey.
Scroll to Top