Основные принципы ООП в Java

Эта статья рассказывает про основные принципы ООП в Java (инкапсуляция, наследовании, полиморфизм и абстракции).

Инкапсуляция в Java

Инкапсуляция - принцип, согласно которому атрибуты объекта заключаются в этот объект. Это задает для атрибутов контекст. Это также позволяет программисту ограничить доступ к атрибутам, чтобы они изменялись и использовались только через методы, которые программист собирается применять:

// Эта переменная не инкапсулирована.
// Поэтому в ней отсутствует какой-то контекст.
String name;
// БАЗОВАЯ ИНКАПСУЛЯЦИЯ
// Эти переменные и методы инкапсулированы в классе Dog. Они являются его членами.
class Dog {
    String name;
    int age;
    void bark() {
        System.out.println("Bark!");
    }
    void rename(String newName) {
        name = newName;
    }
}
// МОДИФИКАТОРЫ ДОСТУПА
// Приведенные выше члены доступны для любого другого
// класса. Чтобы определить доступы, используются модификаторы доступа:
// - default: Если модификаторы доступа отсутствуют, атрибут доступен
//    только для классов внутри одного пакета.
// - public: атрибут доступен из любого другого класса.
// - protected: То же самое, что и default, плюс он доступен для подклассов.
// - private: доступен только внутри объявленного класса.
class Dog {
    private String name;
    private int age;
    void bark() {
        System.out.println("Bark!");
    }
    void rename(String newName) {
        name = newName;
    }
    public String getName() {
        return name;
    }
    public void setAge(int newAge) {
        if(newAge > 0)
            age = newAge;
    }
    public int getAge() {
        return age;
    }
}

Наследование

Наследование – принцип  ООП в Jаva, согласно которому объект может наследовать атрибуты другого объекта. Это позволяет программисту создавать похожие объекты без повторного переопределения атрибутов:

// Если мы хотим определить собак, кошек и птиц, и мы знаем, что у всех этих
// животных есть имена и возраст, мы должны создать суперкласс.
// СУПЕРКЛАСС
class Animal {
    private String name;
    private int age;

    public void identify() {
        System.out.println("I am an animal!");
    }

    public void rename(String newName) {
        name = newName;
    }

    public String getName() {
        return name;
    }

    public void setAge(int newAge) {
        if(newAge > 0)
            age = newAge;
    }

    public int getAge() {
        return age;
    }
}

// ПОДКЛАССЫ
class Dog extends Animal {
    public void bark() {
        System.out.println("Bark!");
    }
}

class Cat extends Animal {
    public void meow() {
        System.out.println("Meow!");
    }
}

class Bird extends Animal {
    public void chirp() {
        System.out.println("Chirp!");
    }
}

В теоретических основах ООП это означает, что каждая собака, кошка и птица (подклассы) будут иметь атрибуты имени и возраста. А также метод Identify, потому что они являются животными (принадлежат суперклассу Animal).

Полиморфизм

Полиморфизм означает «иметь много форм», что, честно говоря, не очень помогает в определении. Мне нравится формулировать это так: используется один и тот же метод, только по-разному. Есть два способа реализации полиморфизма:

Перегрузка: имя метода остается неизменным, но параметры, возвращаемый тип и количество параметров могут изменяться:

// ПЕРЕГРУЗКА
// Класс Animal реализует 3 метода конструктора, которые перегружаются.
// Это означает, что мы можем создать новое животное тремя разными способами.
class Animal {
    private String name;
    private int age;
    Animal() {
        name = "Fred";
        age = 12;
    }
    Animal(String nm) {
        name = nm;
        age = 5;
    }
    Animal(String nm, int newAge) {
        name = nm;
        age = newAge;
    }
    
    
    
}

Перегрузка в основах ООП – это когда метод подкласса имеет то же имя, параметры и возвращаемый тип, что и метод в суперклассе, но реализуется по-другому:

// СУПЕРКЛАСС
class Animal {
    
    
    
    public void identify() {
        System.out.println("I am an animal!");
    }

}

// ПОДКЛАСС
class Dog extends Animal {
    public void bark() {
        System.out.println("Bark!");
    }

    public void identify() {
        System.out.println("I am a dog!");
    }
}

class Cat extends Animal {
    public void meow() {
        System.out.println("Meow!");
    }

    public void identify() {
        System.out.println("I am a cat!");
    }
}

class Bird extends Animal {
    public void chirp() {
        System.out.println("Chirp!");
    }

    public void identify() {
        System.out.println("I am a bird!");
    }
}

Несколько правил переопределения метода в основах ООП Java:

  • Методы подкласса должны иметь одинаковый возвращаемый тип и аргументы;
  • Уровень доступа метода подкласса не может быть более низким, чем у метода суперкласса;
  • Метод, объявленный завершенным или статическим, нельзя переопределить;
  • Если метод не может быть унаследован, его нельзя переопределить.

Абстракция в ООП на Java

Абстракция – в основах ООП для начинающих это процесс скрытия всего, кроме релевантной информации об объекте. Например, нам не нужно знать, как работают часы, чтобы использовать их для определения времени. Абстракция позволяет сосредоточиться на том, что делает объект, а не на том, как он это делает:

// ОСНОВНАЯ АБСТРАКЦИЯ
// Мы можем использовать System.out.println("Hello"), чтобы вывести строку на 
// консоль и не заботиться о том, как работает метод println.
// АБСТРАКТНЫЕ КЛАССЫ
// Абстрактные классы содержат только объявление метода. Их назначение -
// выполнять роль суперклассов для других классов. Они не определяют, как
// методы реализуются, а только что они реализуют. Абстрактные классы не могут
// быть установлены, и подклассы ДОЛЖНЫ реализовать абстрактные методы.
abstract class FlyingAnimal {
    public abstract void Fly();
}
class Bird extends FlyingAnimal {
    protected String name;
    protected int age;
    Bird(String nm, int newAge) {
        name = nm;
        age = newAge;
    }
    @Override
    public void Fly() {
        System.out.println("Flaps wings majestically.");
    }
}
// ИНТЕРФЕЙС
// Классы могут наследоваться только от одного суперкласса, но они могут 
// реализовать несколько интерфейсов. Это расширяет возможности для применения
// абстракции. Классы, которые реализуют интерфейс, ДОЛЖНЫ реализовать
// методы в интерфейсе.
// Стандартные классы
class Animal {
    private String name;
    private int age;
    public void identify() {
        System.out.println("I am an animal!");
    }
    public void rename(String newName) {
        name = newName;
    }
    public String getName() {
        return name;
    }
    public void setAge(int newAge) {
        if(newAge > 0)
            age = newAge;
    }
    public int getAge() {
        return age;
    }
}
// Интерфейс для животных, которые могут летать. Нам нет дела до того,
// как они летают, просто они могут летать.
public interface ICanFly {
    void Fly();
}

// Интерфейс для животных, которые могут плавать. Нам нет дела до того,
// как они плавают, просто они могут плавать.
public interface ICanSwim {
    void Swim();
}
// Утка - это животное, которое может и летать, и плавать.
class Duck extends Animal implements ICanFly, ICanSwim {
    public void Quack() {
        System.out.println("QUACK!");
    }
    @Override
    public void Identify() {
        System.out.println("I am a duck!");
    }
    @Override
    public void Fly() {
        System.out.println("Flaps wings majestically.");
    }
    @Override
    public void Swim() {
        System.out.println("Kicks feet.");
    }
}
// Рыба - это животное, которое умеет плавать. Обратите внимание на то, что 
// реализация метода Swim отличается для утки и для рыбы.
class Fish extends Animal implements ICanSwim {
    @Override
    public void Identify() {
        System.out.println("I am a fish!");
    }
    @Override
    public void Swim() {
        System.out.println("Wiggles fish-body");
    }
}
// Самолет - это не животное, но он все равно может летать.
class AirPlane implements ICanFly {
    protected String name;
    protected int mileage;
    @Override
    public void Fly() {
        System.out.println("Turns propeller");
    }
}

Если я в чем-то ошибся описывая 4 принципа ООП в Java  или вы чего-то не поняли про объектно ориентированное программирование Java, напишите об этом в комментариях.

Вадим Дворниковавтор-переводчик статьи «Four Principles of Object-Oriented Programming with Examples in Java»