Inheritance
- Suppose you are writing software for a bank. You will have both checking and savings accounts.
- What methods does your
SavingsAccount class need?
- What methods does your
CheckingAccount class need?
- Differences:
SavingsAccount only could have payInterest
CheckingAccount could have cashCheck
- Both have a
printStatement
- Notice that both classes are nearly identical. They share some code, and are unique in some ways also.
- Because of the DRY principle (and general laziness), we want to avoid duplicating code.
- The principal of inheritance allows us to create a class by extending and/or modify the behavior of another.
- Refactor the common code into a
BankAccount class.
class CheckingAccount extends BankAccount
CheckingAccount behaves as if it contains all of the BankAccount code. (Imagine that you cut-and-paste all of the BankAccount code into CheckingAccount)
- You can modify behavior by
- Adding additional methods (e.g.,
cashCheck)
- Replacing methods (e.g.,
printStatement)
- This is called overriding
- Use the
@override annotation to help avoid bugs.
- If you need to refer to the parent class, use
super
- e.g.,
super(foo, bar) to invoke parent constructor.
- e.g.,
super.printStatement to print the user’s information.
- Visibility
public Anybody has access to the field/method.
private field/method is only visible within the class.
protected field/method visible within the class and in subclasses
- “package protected” field/method visible within the same package.
- Multiple Inheritance:
- Having two different parent classes (e.g.,
Student and Employee)
- Controversial idea.
- Some languages (C++) support multiple inheritance
- What kind of issues need to be addressed with multiple inheritance?
- What if both parents have methods with the same name?
- What if both parents have fields with the same name? (Do you have two separate
name objects?)
- Java does not. If you think you need multiple inheritance, use one parent class and an interface.
- Use
super to refer to the parent class when necessary
- You can call methods in the parent class if they provide part of the algorithm.
- You call
super as the first line in the constructor to specify which parent constructor to use.
Inheritance in the “real world” / Abstract classes
- GUI
JButton, JPanel, JTextField, etc. are all JComponents.
JComponent provides basic functionality such as placing and drawing.
- Child classes specialize the details of the look and behavior.
- There is a lot of inheritance in JavaSwing.
InputStream, OutputStream
- What is the basic operation of an
InputStream?
- Once you know how to read one byte, reading a group of bytes is just a “convenience” feature.
- Think about an
InputStream from various sources (Keyboard, File, Network).
- Given the specialized code to read one byte, the other
InputStream methods could be identical.
- This is why
InputStream is a parent class and not just an interface: We want to implement some of the methods.
- However, there is no sensible default implementation for
read.
- Thus, we mark it abstract. This means that it has no implementation: The implementation is left for the subclasses.
- An abstract class is any class with at least one abstract method.
- You can’t instantiate abstract classes. (What would happen if you called the abstract method?)
“Gotchas”:
- Avoid shadowing instance variables: It leads to hard-to-find bug.
- Use
@override annotation to catch other subtle bugs.
- Design principle: Prefer Aggregation over Inheritance.
- Inheritance is used for an “is-a” relationship (a checking account is a bank account)
- Don’t use inheritance if the relationship is a “has-a” relationship.
- For example, don’t use inheritance to give a
Car an Engine. A car “has-an” engine. A car is not an engine.
- Don’t use inheritance when the same effect can reasonably be obtained using fields or properties.
- For example: Don’t create
RedDog and BlackDog classes if all you really need is a color instance variable. Save inheritance for significant differences in behavior that can not be described concisely with a few instance variables.
- One reason to avoid overusing inheritance is that it is difficult to unit test thoroughly.
Polymorphism
- Notice that the method that is run is determined by the type of the object, not the type of the variable. For example, even though the variable type is
Animal, the correct speak method is called. This behavior is called polymorphism.
- In the case of an interface, it is the only sensible behavior.
- Just remember it applies to inheritance as well (e.g.,
pay in the lab.)
- Show UML arrows.