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.