إعادة استخدام السلوك باستخدام extends
في هذا الدرس 11 موضوعات
هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.
Lesson Overview
In the last module you hid data behind methods so that a class protects its own rules. Your Account class now works well. Then the bank asks for a savings account that earns interest. A savings account still has an owner, a balance, deposits, and withdrawals. Copying the whole Account class and adding one method would work today, and cause trouble tomorrow: every bug fix would have to be made twice.
This lesson introduces inheritance: a new class can be declared as a kind of an existing class and receive its fields and methods automatically. We will use a family tree as the picture. A child gets traits from a parent but can also have traits of its own.
Why this matters: Java frameworks and libraries are full of classes that extend other classes. Reading and writing extends is a basic skill for backend work.
This lesson builds on the previous module: classes, objects, private, and protected. It uses the Account idea you already know.
Learning Objectives
By the end of this lesson you will be able to:
- Declare a subclass with
extendsand name the superclass and subclass in a given pair. - Say what a subclass receives from its superclass and what it does not (private members, constructors).
- Add new fields and methods to a subclass.
- Explain why a Java class has exactly one direct superclass.
- Apply the is-a test to decide whether
extendsfits. - Read the compiler error produced when a subclass touches a private field of its parent.
Written Explanation
The problem: the same code twice
Imagine Account has an owner, a balance, deposit, and withdraw. A SavingsAccount needs all of that, plus an interest rate. If you copy Account, you now maintain two classes with identical code. When you find a bug in withdraw, you must remember to fix it in both. Programmers call this duplication, and it is a main source of bugs that fix themselves in one place only.
extends: declaring a kind-of relationship
Inheritance lets you write the shared code once. The keyword is extends:
class SavingsAccount extends Account {
// new things only
}Vocabulary you will see everywhere:
| Term | Meaning | In the example |
|---|---|---|
| Superclass (also parent or base class) | The class being extended | Account |
| Subclass (also child or derived class) | The class that extends | SavingsAccount |
| Direct superclass | The one named after extends | Account |
The Java tutorial on inheritance describes the subclass as inheriting the members of its superclass, and says it can add fields and methods of its own. In the family-tree picture, SavingsAccount is the child, Account is the parent, and the child receives the parent's traits.
What a subclass receives
When SavingsAccount extends Account, every SavingsAccount object can use the accessible members of Account as if it had written them itself. Whether a member is accessible follows the access rules from the previous module:
| Member of the parent | Does the subclass get it? |
|---|---|
public fields and methods | Yes |
protected fields and methods | Yes |
| Package-private (no modifier) | Yes, if the subclass is in the same package; otherwise no |
private fields and methods | No (not inherited) |
| Constructors | No (constructors are not members, so they are not inherited) |
A private field is the subtle case. The SavingsAccount object does hold the parent's private data inside it, because the object must store the balance somewhere. But the subclass code cannot name that field. It can only reach it through the parent's public or protected methods. That is encapsulation still doing its job: a subclass does not get to break the parent's rules.
Constructors are the other exception. A constructor builds a particular class, so it is not handed down. The next lesson shows how a subclass constructor asks the parent's constructor to do its part.
New members and the family tree
A subclass is the parent plus something. It can add fields and methods that the parent does not have:
class SavingsAccount extends Account {
private double rate; // new field
void addInterest() { ... } // new method
}A SavingsAccount object has everything from Account and also rate and addInterest(). The reverse is not true: a plain Account has no addInterest(). The parent knows nothing about its children, just as a parent's traits do not depend on what a child later becomes.
One parent only
A Java class has exactly one direct superclass. The language specification (JLS section 8.1.4) says the extends clause names a single class, so you cannot write class C extends A, B. A class without any extends has Object as its direct superclass, and Object is the top of every chain. So every class you have written so far already extends Object without saying so, and every class has a chain of ancestors ending at Object.
A class can have many children; it just cannot have many parents. A class can also implement interfaces, which is a different mechanism and a later topic.
The is-a test
Inheritance is a promise: a subclass object can be treated as a kind of its superclass. Before writing extends, say the sentence out loud:
- "A savings account is an account." Yes:
extendsfits. - "A dog is an animal." Yes.
- "A car is an engine." No: a car has an engine.
If the sentence sounds wrong, extends is wrong, however much code it would save. Lesson 5 goes deeper into the alternative. Saving typing is a pleasant side effect of inheritance, not its purpose.
What the compiler says about private parent data
Because private members are not inherited, this does not compile:
class Account {
private double balance = 100;
double getBalance() { return balance; }
}
class SavingsAccount extends Account {
void addBonus() {
balance += 10;
}
}Main.java:8: error: balance has private access in Account
balance += 10;
^
1 errorThe fix is not to make balance public. Add a method to the parent that applies the rule (a deposit), and let the child call it.
Examples
Example 1: Animal and Dog (simple)
class Animal {
String name = "unnamed";
void eat() {
System.out.println(name + " is eating");
}
}
class Dog extends Animal {
void fetch() {
System.out.println(name + " fetches the ball");
}
}
public class Main {
public static void main(String[] args) {
Dog d = new Dog();
d.name = "Rex";
d.eat();
d.fetch();
}
}Output:
Rex is eating
Rex fetches the ballDog never declares name or eat(), yet it uses both. fetch() is new in Dog. (A package-visible field is used here only to keep the first example short; real classes hide their fields.)
Example 2: SavingsAccount reuses Account (practical)
class Account {
private final String owner;
private double balance;
Account(String owner, double balance) {
this.owner = owner;
this.balance = balance;
}
String getOwner() { return owner; }
double getBalance() { return balance; }
void deposit(double amount) {
if (amount <= 0) {
System.out.println("Deposit refused");
return;
}
balance += amount;
}
}
class SavingsAccount extends Account {
private double rate;
SavingsAccount(String owner, double balance, double rate) {
super(owner, balance); // explained in the next lesson
this.rate = rate;
}
void addInterest() {
deposit(getBalance() * rate);
}
}
public class Main {
public static void main(String[] args) {
SavingsAccount s = new SavingsAccount("Sara", 1000, 0.05);
s.deposit(100);
s.addInterest();
System.out.println(s.getOwner() + " has " + s.getBalance());
}
}Output:
Sara has 1155.0SavingsAccount never touches balance directly. It calls the inherited getBalance() and deposit(...), so the parent's rule (no non-positive deposits) still applies to interest. The line super(owner, balance); is a preview: constructors are not inherited, so the child must call the parent's. Lesson 2 explains it fully; for now copy the pattern.
Example 3: Employee and Manager (realistic)
A company system has employees who are paid, and managers who are employees that also manage a team:
class Employee {
String name;
double salary;
void pay() { System.out.println(name + " is paid " + salary); }
}
class Manager extends Employee {
int teamSize;
void report() { System.out.println(name + " manages " + teamSize + " people"); }
}Creating a Manager, setting name = "Omar", salary = 3000, teamSize = 4, then calling pay() and report() prints:
Omar is paid 3000.0
Omar manages 4 peopleIf a pay bug appears in Employee.pay(), fixing it once fixes managers too. This is the real benefit: one place to change. Notice that Manager also has methods nobody wrote: calling toString() on a manager works because Employee itself extends Object.
Backend Insight
Backend frameworks are built on "extend this class" ideas. You will meet base classes provided by a framework that your own class extends to plug into it. Understanding what you receive from a parent, and what you must not touch, is how you read that code safely.
Inheritance also affects how long-lived code changes. If a parent class changes, every child changes with it, because they share the code. That is powerful when you fix a bug once. It is dangerous when the parent's authors do not know who extends it. Backend teams therefore choose parents deliberately: a shared base class used by dozens of services is a contract that is expensive to change.
Common Mistakes
Mistake 1: Using extends only to save typing
- Incorrect:
class Invoice extends Accountbecause both have an amount. - Correct: ask "is an invoice an account?" Since it is not, keep them separate classes.
Mistake 2: Expecting to inherit private members
A subclass cannot read or write the parent's private fields by name. Use the parent's public or protected methods.
Mistake 3: Expecting to inherit constructors
SavingsAccount does not get Account(String, double). You must write a constructor in the subclass.
Mistake 4: Trying to extend two classes
class C extends A, B {}
Main.java:3: error: '{' expectedJava allows a single superclass. Pick the true parent and use other tools (such as holding an object in a field, Lesson 5) for the rest.
Mistake 5: Expecting the parent to know the child's members
An Account object has no addInterest(). The new methods exist only on the subclass.
Exercises
Try each exercise yourself before opening the solutions.
Level A: Foundation
A1. Name the superclass and the subclass: class Cat extends Animal.
أظهر الحل A1
A1. Superclass: Animal. Subclass: Cat.
A2. Apply the is-a test and answer yes or no for extends: (a) Teacher / Person, (b) Wheel / Car, (c) Circle / Shape.
أظهر الحل A2
A2. (a) Yes: a teacher is a person. (b) No: a car has wheels. (c) Yes: a circle is a shape.
A3. Can a subclass use a public method of its parent without redeclaring it? A private one?
أظهر الحل A3
A3. A public method: yes, it is inherited. A private one: no, the subclass cannot use it by name.
Level B: Application
B1. Product has name, price, and label() that returns name + " costs " + price. Write DiscountedProduct extends Product with a discount field and a finalPrice() method. What does label() return for a product named Lamp priced 50?
أظهر الحل B1
B1.
class DiscountedProduct extends Product {
double discount;
double finalPrice() {
return price - discount;
}
}label() is inherited, so for Lamp priced 50 it returns Lamp costs 50.0. (Running a discount of 8 gives finalPrice() of 42.0.)
B2. This does not compile. Explain why and give a fix without making the field public.
class Counter { private int count; }
class StepCounter extends Counter {
void step() { count++; }
}أظهر الحل B2
B2. count is private in Counter, so StepCounter cannot name it. Fix: give Counter a method such as protected void increment() { count++; } (or a public one) and call increment() from step(). The parent keeps control of its field.
B3. Report has a public print(). PdfReport extends Report adds export(). Which of these calls are valid on a PdfReport object: print(), export()? On a plain Report object?
أظهر الحل B3
B3. On a PdfReport both print() (inherited) and export() are valid. On a plain Report only print() is valid, because the parent does not have export().
Level C: Challenge
C1. A teammate writes class OrderItem extends Order because an order item needs the order's date. Explain what is wrong with the design in two sentences, and say what the item should do instead (a hint is in the Common Mistakes above).
أظهر الحل C1
C1. An order item is not a kind of order: it is a part of one, so the is-a test fails, and a shared date is not a reason to inherit. The item should hold a reference to its Order in a field (or receive the date as a constructor argument) instead of extending it.
C2. Draw the ancestor chain of Manager from Example 3 down to the very top, listing every class.
أظهر الحل C2
C2. Manager extends Employee, which extends Object. So the chain is Manager, Employee, Object.
Mini Challenge
Create a Vehicle class with a field brand (private, with a getter) and a method describe() that prints the brand. Create a Truck extends Vehicle with a loadCapacity field and a method that prints it. In main, create a truck and call both methods. Then add a line inside Truck that reads brand directly, read the compiler error, and remove the line.
Check your work: Truck reuses describe() without redeclaring it, and the direct access to brand is rejected by the compiler.
Summary & Next Lesson
Key takeaways
class Child extends ParentmakesChilda subclass that receives the accessible members ofParentand can add its own.- Private members and constructors are not inherited.
- A class has exactly one direct superclass; a class with no
extendshasObjectas its superclass. - Use the is-a test before
extends. Code reuse alone is not a reason. - Fix a bug in the parent once and all children benefit, which is both the strength and the risk.
Next lesson
You saw super(owner, balance) once, as a preview. The next lesson, "Constructors and super", explains how the parent part of an object is built and what the compiler requires.
Self-check
- Which keyword makes one class a subclass of another?
- Can a class have two direct superclasses?
- Is a private field of the parent inherited by name? What gives the child access?
- Which class is at the top of every class's ancestor chain?
- A
Libraryclass holds manyBookobjects. DoesLibrary extends Bookpass the is-a test?
أظهر الإجابات
extends.- No. Exactly one direct superclass.
- No. The child uses the parent's public or protected methods.
Object.- No. A library is not a kind of book; it has books.
References
- Oracle, Java Tutorials, Inheritance. Supports what a subclass inherits: public and protected members, not private members or constructors, and the idea of adding new members.
- Oracle, Java Language Specification SE 21, Section 8.1.4, Superclasses and Subclasses. Supports the single direct superclass rule and
Objectas the default superclass. - The family-tree analogy, the is-a test wording, and the
Accountexamples are this course's own teaching choices. The code was compiled and run with JDK 21 and the output shown is real.
التطبيق
طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.
تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.