Object Inheritance Flashcards
What is inheritance and why is it used?
In the 1980s software systems began growing rapidly in complexity, making it harder and harder to manage the code. Especially in the development of graphical user interfaces like Windows and Mac applications: many of the graphical components of an application, or even of different applications (windows, menus, pop-ups, check boxes, etc.) were very similar, but had specific aspects of the object that needed to be different. Menu bars, drop-down menus, and checkbox lists all need to present a set of choices to users, allow them to select one or many items, give then appropriate feedback, and the take actions specific to an application. If every one of these was written independently, you can imagine that lots of duplicate code and duplicate effort would be required. And then, if an enhancement was proposed or a problem found in the duplicated code, even more duplicate effort would be required.
To deal with this in programming, techniques were developed to allow specific objects to be built from more general-purpose ones, re-using some (or most!) of the attributes and behaviors of the ones higher in the tree, but adding to or modifying them as needed. This method of sharing general purpose code based on relationships is called inheritance.
Inheritance is a way to create formal relationships between the subclasses (the more specific ones) and the super classes directly above them in the tree. Subclasses “inherit” behavior from their parents. However, the names can be confusing. A subclass actually has more data and more methods than a super class, because it contains whatever is inherited and then whatever is built on top of that. We think of these objects as being either above (“super”) or below (“sub”) one another creating a sort of tree of relationships with the super class at the top and the sub classes branching out beneath it.
We’ll look at this using an example from the biological “kingdom” of Animals. In our simple world, all animals have a digestive system and a nervous system, and all eat food and “breathe” (convert oxygen into carbon dioxide). We’ll divide Animals further into Birds and Horses, which inherit all these attributes and behaviors, but while Horses have four legs and gallop, our Birds have two legs and two wings and fly. Penguins are birds, but sadly cannot fly, and turkeys fly very poorly. Other birds like eagles and robins fly perfectly well, and also have some additional behaviors: eagles glare, and robins get up early.
How would one use the keyword “extends”?
Let’s see how this high-level inheritance diagram becomes Java code. The Animal class is no different than the ones we’ve seen before; for now, we’ve omitted the constructors as we will discuss them in the next section.
public class Animal {
private DigestiveSystem dSys;
private NervousSystem nSys;
public void eat() {
findFood();
ingestFood();
}
public void breathe() {
extractO2();
produceCO2();
}
}
Note that its fields can be objects.
Both Bird and Horse are subclasses of Animal, so in Java we will use the keyword extends to indicate this relationship:
public class Bird extends Animal {
private boolean flightless;
public void fly() {
if (!flightless) {
soar();
}
}
private void soar() {
…
}
public class Horse extends Animal {
public void gallop() {
…
}
By adding the “extends ParentClass” syntax to the header we are telling Java that this child should inherit all the parent’s public fields and methods. You can imagine that code is copied and pasted into the child class as you can now use it as if it exists within that class. Subclasses do not inherit private instance variables or private methods from their super class.
You can also build on top of what you inherit. Anything you add to the child class will be combined with whatever is inherited to form the complete state and behavior of this object.
As you can see in the diagram Bird.java has 3 fields: DigestiveSystem and NervousSystem which are inherited from Animal.java and flightless, that it added itself. The same idea of adding onto what is inherited applies to methods as well.
What does it mean to “override” inherited methods?
Sometimes the things you inherit aren’t exactly what you want in your child class. If this is the case you can “override” those methods which replaces whatever is inherited with whatever is explicitly defined in the child class.
Let’s say Birds have a very different way of eating than Animals. Birds inherit the following eat method from Animal:
public void eat() {
findFood();
ingestFood();
}
To replace this method in our Bird class we simply have to copy the exact method header and implement whatever we need in the child class:
public class Bird extends Animal {
private boolean flightless;
public void eat() {
surveyLand();
findFood();
deliverToNest();
}
…
}
Now when we call eat() in the Bird class it will run that version of the method, not in inherited one.
What is an “is-a relationship”?
The relationships we’ve been exploring with inheritance are often referred to as an Is-A relationship: a Bird Is-A(n) Animal, a Robin Is-A Bird, and significantly a Robin Is-A(n) Animal too. The family tree provides a clue here, if your great-great-great-grandmother was a Smith, you’re a Smith too (at least in her view!). In fact, the very top of the object tree for any object is a very special Java class, the Object class – which is why a Bird Is-A(n) Object! In other words, has an Is-A relationship with every one of its super classes, right up to the top of the tree.
When you look at the inheritance tree of a set of classes the “is-a” relationships move up the tree. More specific classes can be considered subsets of their parents. In the above example all Teachers are Staff. The relationship does not go down the tree, not every Student is a Freshman.
What is a “has-a” relationship?
The other type of relationship is has-a which refers to when an object contains another within it. An Animal Has-A DigestiveSystem, and a Bird Has-A number of Legs. A class’s Has-A relationships are typically with fields that are objects, not with their super classes.
When you’re designing classes, asking yourself whether two objects have an Is-A or a Has-A relationship is a good way to figure out whether you should extend one from the other, or include one as an attribute of the other.
What does the “super” keyword do?
When a class extends another it establishes a hierarchy between the two. The class that “extends” the other is the child, making the other class the parent or “super class”.
Basic inheritance means the subclass gets exact copies of everything in the super class, but you can actually adjust what you inherit and what you don’t using the super keyword in your child class.
In the example below, the “School Member” is the overall super class. Staff is the super class of Teachers and Administrators and Student is the super class of Freshmen and Seniors.
You can use the super keyword to call a super class’s code from within the child class.
What happens if the super class has a non default constructor defined?
So far the only keyword you’ve had to use to inherit things is “extends”. By adding that to your class header you automatically inherit all fields and methods. You may not have noticed, but all along you’ve also been automatically inheriting the default constructor. In effect, Java provides this code so you don’t have to
However, if the super class has a non default constructor defined- that is not inherited. If you have a non default constructor in your super class, you must implement a constructor in the child class. Chances are that constructor will be very similar to the super class constructor as you likely are just initializing all the fields in the child class in the same way you are in the super class. You can resolve that redundancy by using “super” to call the super class constructor like so:
public class Student {
public Student(String name) {
super(name);
}
}
This calls the super class constructor and passes along the parameters to initialize the fields. If you are going to use the super constructor in your child class you MUST put the super() call as the first thing in your constructor. You can’t make a Teacher until you have a Staff, you can’t make a Staff until you have an SchoolMember, and you can’t make an SchoolMember until you have an Object!
What is polymorphism?
When a method is overridden in a subclass you create an inheritance structure where the same method may have different behaviors. This method is then said to be polymorphic.
Due to is-a relationships, in Java you can declare variables where the object reference and the actual object can be different.
Given the hierarchy below, all of the following are valid variable declarations:
Dog a = new Dog();
Dog b = new Sporting();
Sporting c = new LabradorRetriever();
Dog d = new GoldenRetriever();
If the Dog class contains a method like “bark()” it will be inherited by all its subclasses. However, its possible for each class to override that method and add their own implementation of bark():
public class Dog {
public String bark() {
return “woof”;
}
}
public class Sporting extends Dog {
public String bark() {
return “howl”;
}
}
public class LabradorRetriever extends Sporting {
public String bark() {
return “high howl”;
}
}
Now, which implementation is called on each of our variables? In Java it is always the “actual object”, to the right of the equals sign, who’s implementation is called upon.
Dog a = new Dog();
Dog b = new Sporting();
Sporting c = new LabradorRetriever(); System.out.println(a.bark()); // prints “woof” System.out.println(b.bark()); // prints “howl” System.out.println(c.bark()); // prints “high howl”
The key to using polymorphism is to remember that when any method is called, it is the type of the object that determines what code is executed.
What is an abstract class?
An abstract class is one that exists for the sake of inheritance, but doesn’t actually make sense in reality and thus should never actually be instantiated with the keyword “new”.
In our Animal examples we always have a top node like “Animal” or “Dog”, which serves the purpose to create code that will be shared by the subclasses, however there is no such thing as just an “Animal”. To help your user know that they should never actually create a copy of this type of class you can make it abstract.
public abstract Animal {
An abstract class may also contain abstract methods. These are methods without implementation, only a method header. By adding an abstract method you guarantee that all your subclasses add their own implementation. This prevents you from writing unnecessary code to implement a method in a super class which will always be overridden in the subclasses.
An abstract class may or may not have a constructor. It does not need a constructor as it will never be called, but you can add one if you want to be able to call it from the sub classes.
public abstract Animal {
abstract Animal produceOffspring();
abstract boolean consumeFood();
}
You can only declare abstract methods within abstract classes, however an abstract class can contain fully implemented methods as well.
public abstract Animal {
public Distance move() {
return new Distance(1);
}
abstract Animal produceOffspring();
}
What are interfaces?
In Java, a class can only ever inherit from one super class. This can be rather limiting when you have a large ecosystem of code and you want to form more relationships than simple inheritance allows. Another way to relate objects to one another is through something called an **interface**. An interface is a contract that dictates a minimum amount of behavior. You can think of it like a list of abstract methods, or method headers, that are required to be implemented in any object using the interface.
public interface Flying {
public int wings();
public boolean takeOff();
public boolean land();
}
An interface allows you to relate objects based on their behavior, not just which code they should share. For example, both birds and insects may implement the Flying interface, but they might not share a common parent class.
To apply an interface to an object you use the keyword “implements”:
public class Falcon implements Flying {
An object can implement as many interfaces as you need, which can come in handy when you’re limited by single inheritance rules.
public class Bee extends Insect implements Flying, Hibernating, Stinging {
Java already has some popular interfaces: