«1. Обзор
В этой статье мы рассмотрим концепции объектно-ориентированного программирования (ООП) в Java. Мы обсудим классы, объекты, абстракцию, инкапсуляцию, наследование и полиморфизм.
2. Классы
Классы являются отправной точкой всех объектов, и мы можем рассматривать их как шаблон для создания объектов. Класс обычно содержит поля-члены, методы-члены и специальный метод конструктора.
Мы будем использовать конструктор для создания объектов класса:
public class Car {
// member fields
private String type;
private String model;
private String color;
private int speed;
// constructor
public Car(String type, String model, String color) {
this.type = type;
this.model = model;
this.color = color;
}
// member methods
public int increaseSpeed(int increment) {
this.speed = this.speed + increment;
return this.speed;
}
// ...
}
Обратите внимание, что класс может иметь более одного конструктора. Мы можем прочитать больше о классах в нашей статье о классах.
3. Объекты
Объекты создаются из классов и называются экземплярами класса. Мы создаем объекты из классов, используя их конструкторы:
Car veyron = new Car("Bugatti", "Veyron", "crimson");
Car corvette = new Car("Chevrolet", "Corvette", "black");
Здесь мы создали два экземпляра класса Car. Подробнее о них читайте в нашей статье об объектах.
4. Абстракция
Абстракция скрывает сложности реализации и открывает более простые интерфейсы.
Если представить обычный компьютер, то можно увидеть только внешний интерфейс, который наиболее необходим для взаимодействия с ним, а внутренние микросхемы и схемы скрыты от пользователя.
В ООП абстракция означает сокрытие сложных деталей реализации программы, открывая доступ только к API, необходимому для использования реализации. В Java мы достигаем абстракции, используя интерфейсы и абстрактные классы.
Мы можем узнать больше об абстракции в наших статьях об абстрактных классах и интерфейсах.
5. Инкапсуляция
Инкапсуляция — это скрытие состояния или внутреннего представления объекта от потребителя API и предоставление общедоступных методов, привязанных к объекту, для доступа на чтение и запись. Это позволяет скрывать конкретную информацию и контролировать доступ к внутренней реализации.
Например, поля-члены в классе скрыты от других классов, и к ним можно получить доступ с помощью методов-членов. Один из способов сделать это — сделать все поля данных закрытыми и доступными только с помощью общедоступных методов-членов: () и setSpeed(). Подробнее о модификаторах доступа можно прочитать в нашей статье о модификаторах доступа.
public class Car {
// ...
private int speed;
public int getSpeed() {
return color;
}
public void setSpeed(int speed) {
this.speed = speed;
}
// ...
}
6. Наследование
Наследование — это механизм, который позволяет одному классу приобретать все свойства другого класса путем наследования класса. Мы называем наследующий класс дочерним классом, а унаследованный класс — суперклассом или родительским классом.
В Java мы делаем это, расширяя родительский класс. Таким образом, дочерний класс получает все свойства от родителя:
Когда мы расширяем класс, мы формируем отношение IS-A. Автомобиль ЕСТЬ-транспортное средство. Таким образом, он обладает всеми характеристиками транспортного средства.
public class Car extends Vehicle {
//...
}
Можно задать вопрос, зачем нам наследование? Чтобы ответить на этот вопрос, давайте рассмотрим производителя транспортных средств, который производит различные типы транспортных средств, таких как автомобили, автобусы, трамваи и грузовики.
Чтобы упростить работу, мы можем объединить общие функции и свойства всех типов транспортных средств в модуль (класс в случае Java). И мы можем позволить отдельным типам наследовать и повторно использовать эти свойства:
Тип автомобиля Car теперь будет наследоваться от родительского класса Vehicle:
public class Vehicle {
private int wheels;
private String model;
public void start() {
// the process of starting the vehicle
}
public void stop() {
// process to stop the vehicle
}
public void honk() {
// produces a default honk
}
}
Java поддерживает одиночное наследование и многоуровневое наследование. Это означает, что класс не может напрямую расширяться более чем из одного класса, но он может использовать иерархию:
public class Car extends Vehicle {
private int numberOfGears;
public void openDoors() {
// process to open the doors
}
}
Здесь ArmouredCar расширяет Car, а Car расширяет Vehicle. Таким образом, ArmouredCar наследует свойства как Car, так и Vehicle.
public class ArmoredCar extends Car {
private boolean bulletProofWindows;
public void remoteStartCar() {
// this vehicle can be started by using a remote control
}
}
Хотя мы наследуем от родительского класса, разработчик также может переопределить реализацию метода от родителя. Это называется переопределением метода.
В приведенном выше примере класса Vehicle есть метод honk(). Класс Car, расширяющий класс Vehicle, может переопределить этот метод и реализовать так, как он хочет производить гудок:
«
public class Car extends Vehicle {
//...
@Override
public void honk() {
// produces car-specific honk
}
}
«Обратите внимание, что это также называется полиморфизмом времени выполнения, как объясняется в следующем разделе. Мы можем прочитать больше о наследовании в наших статьях о наследовании Java, а также о наследовании и композиции.
7. Полиморфизм
Полиморфизм — это способность языка ООП обрабатывать данные по-разному в зависимости от их типов входных данных. В Java это может быть одно и то же имя метода, имеющее разные сигнатуры и выполняющие разные функции:
public class TextFile extends GenericFile {
//...
public String read() {
return this.getContent()
.toString();
}
public String read(int limit) {
return this.getContent()
.toString()
.substring(0, limit);
}
public String read(int start, int stop) {
return this.getContent()
.toString()
.substring(start, stop);
}
}
В этом примере мы видим, что метод read() имеет три разные формы с разными функциями. Этот тип полиморфизма является статическим или полиморфизмом времени компиляции и также называется перегрузкой методов.
Существует также динамический полиморфизм времени выполнения, когда дочерний класс переопределяет метод родителя:
public class GenericFile {
private String name;
//...
public String getFileInfo() {
return "Generic File Impl";
}
}
Дочерний класс может расширять класс GenericFile и переопределять метод getFileInfo():
public class ImageFile extends GenericFile {
private int height;
private int width;
//... getters and setters
public String getFileInfo() {
return "Image File Impl";
}
}
Подробнее о полиморфизме в нашей статье о полиморфизме в Java.
8. Заключение
В этой статье мы узнали об основных фундаментальных концепциях ООП с Java.
Примеры кода в этой статье доступны на Github.