"Hello, Amigo! Now here's a topic I think you'll use a lot. I'm talking about inheritance."

For the uninitiated, programming is like magic. So let me start with an analogy…

Suppose you are a magician who wants to create a flying horse. You could try conjuring a Pegasus. But since flying horses aren't naturally occurring, you'll have a really hard time. You'd have a lot of work to do. It would be much easier to start with a horse and summon some wings.

Inheritance. Advantages of inheritance - 1

In programming, we call this process «inheritance». Suppose you need to write a very complex class. You could spend a long time writing code from scratch, and then perform lengthy testing to find bugs. But why do it the hard way? It's better to look around and see if the class you're looking for already exists?

Let's say you find a class that implements 80% of the functionality you need. You can just copy its code into your class. But that would have several drawbacks:

1) The class you find might already be compiled into bytecode. You might not have access to its source code.

2) You might have the source code for the class, but also work at a company that could be sued for a couple of billion if you use even 6 lines of someone else's code. And then they will sue you.

3) This leads to the unnecessary duplication of lots of code. And if the author of the other class finds a bug and fixes it, you still have the bug.

There is a more elegant solution that doesn't require getting legal permission to the code of the original class. In Java, you can simply declare the other class as the parent of your class. This is equivalent to adding that class's code to your own class. All the data and methods of the parent class will appear in your class. For example, you could inherit from a «horse», add «wings», and get a «Pegasus».

Inheritance. Advantages of inheritance - 2

"Very interesting. Please go on."

"Inheritance has other uses too. Suppose you have ten classes that are very similar. They have matching data and methods. You could create a special base class, move the data (and associated methods) to the base class, and have those ten classes inherit from it. In other words, for each class, you indicate that it has a parent class, also known as a base class."

"Just as the advantages of abstraction are only truly revealed in connection with encapsulation, the advantages of inheritance are magnified by polymorphism. But I'll tell you about that tomorrow. Today let's look at a few examples of inheritance."

"Suppose we're writing a chess program. We'll need classes for the chess pieces. Which classes would you suggest, Amigo?"

"King, Queen, Bishop, Knight, Rook, and Pawn."

"Very good. You didn't miss a thing."

"And what data would you suggest storing in these classes?"

"Each piece's board position (x and y) and worth. After all, some pieces are more valuable than others."

"And what are the differences between these classes?"

"They differ in how they move the pieces. In their behavior."

"Yes. You could define them as classes like this:"

class King
{
int x;
int y;
int worth;
void kingMove()
{
//code that defines,
//how the king moves
}
}
class Queen
{
int x;
int y;
int worth;
void queenMove()
{
//code that defines,
//how the queen moves
}
}
class Rook
{
int x;
int y;
int worth;
void rookMove()
{
//code that defines,
//how the rook moves
}
}
class Knight
{
int x;
int y;
int worth;
void knightMove()
{
//code that defines,
//how the knight moves
}
}
class Bishop
{
int x;
int y;
int worth;
void bishopMove()
{
//code that defines,
//how the bishop moves
}
}
class Pawn
{
int x;
int y;
int worth;
void pawnMove()
{
//code that defines,
//how the pawn moves
}
}

"Yes, that's exactly how I would write it."

"But look at how you could use inheritance to write less code. We can move identical methods and data into a common class. Let's call it ChessItem. It doesn't make sense to create ChessItem objects, since they don't correspond to any chess piece. But the class would be extremely helpful:"

class King extends ChessItem
{
void kingMove()
{
//code that defines,
//how the king moves
}
}
class Queen extends ChessItem
{
void queenMove()
{
//code that defines,
//how the queen moves
}
}
class Rook extends ChessItem
{
void rookMove()
{
//code that defines,
//how the rook moves
}
}
 class ChessItem
{
int x;
int y;
int worth;
}
 
class Knight extends ChessItem
{
void knightMove()
{
//code that defines,
//how the knight moves
}
}
class Bishop extends ChessItem
{
void bishopMove()
{
//code that defines,
//how the bishop moves
}
}
class Pawn extends ChessItem
{
void pawnMove()
{
//code that defines,
//how the pawn moves
}
}

"How interesting!"

"Absolutely! The benefit is especially large in projects containing thousands of different objects and hundreds of classes. In this case, properly chosen classes can not only significantly simplify the logic, but also reduce the required code by a factor of ten."

"So what do you have to do to inherit a class?"

"After declaring a class, we use the keyword 'extends', followed by the name of the parent class. You can only inherit from one class."

Inheritance. Advantages of inheritance - 3

The picture shows a "cow" that has inherited from a «pig». The «Pig» inherits from the «chicken», and the «chicken» inherits from the «egg». Each class has only one parent! Such inheritance is not always logical. If you only have a pig, but you really need a cow, programmers often can't resist the desire to make a «cow» out of the «pig».

"But what if I want to inherit from two classes? Is there anything I can do?!"

"Not really. Java classes do not support multiple inheritance of implementation: a class can only have a single parent class. But there is multiple inheritance of type, which means that a class can implement more than one interface. This slightly mitigates the problem."

"I see. And what is an interface?"

"I'll tell you about interfaces tomorrow. For now, let's continue delving into inheritance."