Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Для чего нужен extends?
Основное назначение
extends — это ключевое слово в Java для наследования (inheritance), которое позволяет одному классу (подклассу/потомку) получить все поля и методы другого класса (суперкласса/родителя).
Это один из трёх столпов объектно-ориентированного программирования (наряду с инкапсуляцией и полиморфизмом).
Синтаксис
public class Parent {
public void parentMethod() {
System.out.println("Parent method");
}
}
public class Child extends Parent {
// Наследует parentMethod() от Parent
// Может переопределить (override) parentMethod()
@Override
public void parentMethod() {
System.out.println("Child method");
}
}
// Использование
Child child = new Child();
child.parentMethod(); // Выведет: "Child method"
Parent parent = new Parent();
parent.parentMethod(); // Выведет: "Parent method"
Основные причины использования extends
1. Повторное использование кода (Code Reuse)
// БЕЗ extends - дублирование кода
class Dog {
public void eat() { System.out.println("Eating"); }
public void sleep() { System.out.println("Sleeping"); }
public void bark() { System.out.println("Bark"); }
}
class Cat {
public void eat() { System.out.println("Eating"); } // Дублирование!
public void sleep() { System.out.println("Sleeping"); } // Дублирование!
public void meow() { System.out.println("Meow"); }
}
// С extends - общий код в одном месте
class Animal {
public void eat() { System.out.println("Eating"); }
public void sleep() { System.out.println("Sleeping"); }
}
class Dog extends Animal {
public void bark() { System.out.println("Bark"); }
}
class Cat extends Animal {
public void meow() { System.out.println("Meow"); }
}
2. Иерархия классов (IS-A отношение)
// Естественная иерархия
class Vehicle {
private String color;
private double speed;
public void move() { /* ... */ }
}
class Car extends Vehicle {
private int numDoors;
public void openTrunk() { /* ... */ }
}
class Bicycle extends Vehicle {
private boolean hasBrakes;
public void ringBell() { /* ... */ }
}
// Использование
Car car = new Car(); // car IS-A Vehicle
Bicycle bike = new Bicycle(); // bike IS-A Vehicle
// Полиморфизм
Vehicle vehicle1 = car; // Car может быть использована как Vehicle
Vehicle vehicle2 = bike; // Bicycle может быть использована как Vehicle
3. Полиморфизм
class Shape {
public void draw() {
System.out.println("Drawing shape");
}
public double area() {
return 0;
}
}
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Drawing circle");
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
class Square extends Shape {
private double side;
public Square(double side) {
this.side = side;
}
@Override
public void draw() {
System.out.println("Drawing square");
}
@Override
public double area() {
return side * side;
}
}
// Полиморфная обработка
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(5));
shapes.add(new Square(4));
for (Shape shape : shapes) {
shape.draw(); // Вызывает переопределённый метод
System.out.println("Area: " + shape.area());
}
// Вывод:
// Drawing circle
// Area: 78.53981...
// Drawing square
// Area: 16.0
Практические примеры
1. Exception иерархия
// Все исключения наследуют Throwable
class Throwable { /* ... */ }
class Exception extends Throwable { /* ... */ }
class RuntimeException extends Exception { /* ... */ }
class NullPointerException extends RuntimeException { /* ... */ }
class IllegalArgumentException extends RuntimeException { /* ... */ }
// Использование
try {
// code
} catch (Exception e) { // Ловит все Exception и его подклассы
e.printStackTrace();
}
2. Collection Framework
// Иерархия Collections
interface Collection<E> { /* ... */ }
interface List<E> extends Collection<E> { /* ... */ }
abstract class AbstractList<E> implements List<E> { /* ... */ }
class ArrayList<E> extends AbstractList<E> { /* ... */ }
class LinkedList<E> extends AbstractList<E> { /* ... */ }
// Использование полиморфизма
List<String> list = new ArrayList<>(); // Можно заменить на LinkedList
list.add("item");
3. Entity иерархия в JPA
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Animal {
@Id
private Long id;
private String name;
public void eat() { /* ... */ }
}
@Entity
public class Dog extends Animal {
private String breed;
public void bark() { /* ... */ }
}
@Entity
public class Cat extends Animal {
private boolean indoor;
public void meow() { /* ... */ }
}
4. Service слой
public abstract class BaseService<T> {
protected Repository<T> repository;
public void save(T entity) {
repository.save(entity);
}
public T findById(Long id) {
return repository.findById(id).orElse(null);
}
public List<T> findAll() {
return repository.findAll();
}
}
@Service
public class UserService extends BaseService<User> {
@Autowired
private UserRepository userRepository;
@Override
protected Repository<User> getRepository() {
return userRepository;
}
public User findByEmail(String email) {
return userRepository.findByEmail(email);
}
}
@Service
public class ProductService extends BaseService<Product> {
@Autowired
private ProductRepository productRepository;
@Override
protected Repository<Product> getRepository() {
return productRepository;
}
public List<Product> findByCategory(String category) {
return productRepository.findByCategory(category);
}
}
Переопределение (Override) vs Перегрузка (Overload)
class Parent {
public void method(String s) {
System.out.println("Parent method");
}
}
class Child extends Parent {
// ПЕРЕОПРЕДЕЛЕНИЕ (Override) - тот же сигнатура
@Override
public void method(String s) {
System.out.println("Child method - override");
}
// ПЕРЕГРУЗКА (Overload) - другая сигнатура
public void method(int i) {
System.out.println("Child method - overload");
}
}
Child child = new Child();
child.method("text"); // Вызовет переопределённый метод
child.method(5); // Вызовет перегруженный метод
super vs this
class Parent {
protected String name = "Parent";
public void greet() {
System.out.println("Hello from Parent");
}
}
class Child extends Parent {
private String name = "Child";
@Override
public void greet() {
super.greet(); // Вызывает метод родителя
System.out.println("Hello from Child");
}
public void printNames() {
System.out.println(this.name); // "Child"
System.out.println(super.name); // "Parent"
}
}
Child child = new Child();
child.greet();
// Hello from Parent
// Hello from Child
child.printNames();
// Child
// Parent
Правила наследования
1. Java поддерживает ТОЛЬКО однократное наследование
✓ class Child extends Parent { }
✗ class Child extends Parent1, Parent2 { } // ОШИБКА!
// Для множественного наследования используют интерфейсы
class Child extends Parent implements Interface1, Interface2 { }
2. Конструктор родителя НЕ наследуется явно
class Child extends Parent {
public Child() {
super(); // НУЖНО вызвать конструктор родителя
}
}
3. Приватные методы НЕ наследуются
class Parent {
private void privateMethod() { } // Не видна в Child
}
4. Статические методы НЕ переопределяются (скрываются)
class Parent {
public static void staticMethod() { }
}
class Child extends Parent {
public static void staticMethod() { } // Не override, а hiding
}
5. Нельзя сузить видимость при переопределении
class Parent {
public void method() { } // public
}
class Child extends Parent {
protected void method() { } // ОШИБКА! Нельзя сузить видимость
}
Когда НЕ использовать extends
✗ НЕ используй extends когда:
1. HAS-A отношение (композиция лучше)
// Плохо
class Person extends ArrayList { } // Человек НЕ ЯВЛЯЕТСЯ списком!
// Хорошо
class Person {
private List<String> hobbies = new ArrayList<>();
}
2. Нужна гибкость (используй интерфейсы)
// Плохо
class MyClass extends BaseClass { }
// Хорошо
class MyClass implements MyInterface { }
3. Только для перегруппировки кода (используй композицию)
Итог
extends используется для:
- Повторного использования кода — наследование методов и полей
- Создания иерархии классов — IS-A отношения
- Реализации полиморфизма — один объект может выступать разными типами
- Применения наследования при дизайне — создание расширяемых и гибких систем
- DRY принципа — не дублируй код, наследуй
Наследование — это мощный инструмент, но его нужно использовать правильно. Часто лучше использовать интерфейсы (implements) или композицию вместо наследования (extends).