Перейти к основному содержимому

Концепции объектно-ориентированного программирования в Java

· 6 мин. чтения

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 и предоставляет общедоступные методы, привязанные к объекту, для доступа на чтение и запись. Это позволяет скрывать конкретную информацию и контролировать доступ к внутренней реализации.

Например, поля-члены в классе скрыты от других классов, и к ним можно получить доступ с помощью методов-членов. Один из способов сделать это — сделать все поля данных закрытыми и доступными только с помощью общедоступных методов-членов:

public class Car {

// ...
private int speed;

public int getSpeed() {
return color;
}

public void setSpeed(int speed) {
this.speed = speed;
}
// ...
}

Здесь скорость поля инкапсулируется с помощью модификатора закрытого доступа, и доступ к ней возможен только с помощью общедоступных методов getSpeed() и setSpeed() . Подробнее о модификаторах доступа можно прочитать в нашей статье о модификаторах доступа .

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

Наследование — это механизм, который позволяет одному классу приобретать все свойства другого класса путем наследования класса. Мы называем наследующий класс дочерним классом, а унаследованный класс — суперклассом или родительским классом.

В Java мы делаем это, расширяя родительский класс. Таким образом, дочерний класс получает все свойства от родителя:

public class Car extends Vehicle { 
//...
}

Когда мы расширяем класс, мы формируем отношение IS-A . Автомобиль ЕСТЬ- транспортное средство . Таким образом, он обладает всеми характеристиками транспортного средства .

Мы можем задать вопрос, зачем нам наследование ? Чтобы ответить на этот вопрос, давайте рассмотрим производителя транспортных средств, который производит различные типы транспортных средств, таких как автомобили, автобусы, трамваи и грузовики.

Чтобы упростить работу, мы можем объединить общие функции и свойства всех типов транспортных средств в модуль (класс в случае Java). И мы можем позволить отдельным типам наследовать и повторно использовать эти свойства:

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
}

}

Тип автомобиля Car теперь будет наследоваться от родительского класса Vehicle :

public class Car extends Vehicle {
private int numberOfGears;

public void openDoors() {
// process to open the doors
}
}

Java поддерживает одиночное наследование и многоуровневое наследование. Это означает, что класс не может напрямую расширяться более чем из одного класса, но может использовать иерархию:

public class ArmoredCar extends Car {
private boolean bulletProofWindows;

public void remoteStartCar() {
// this vehicle can be started by using a remote control
}
}

Здесь ArmouredCar расширяет Car , а Car расширяет Vehicle . Таким образом, ArmouredCar наследует свойства как от Car , так и от Vehicle .

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

В приведенном выше примере класса 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 .