Skip to content

Latest commit

 

History

History
562 lines (458 loc) · 29.1 KB

File metadata and controls

562 lines (458 loc) · 29.1 KB

Занятие 5. Классы и объекты (I)

Классы

Объект представляет (моделирует) конкретную сущность: вещь реального мира или абстрактное понятие, например, автомобиль, студента, товар в магазине, банковский счет, событие в календаре, процесс заказа в интернет-магазине, число, строку, список, прямоугольник и т. п.

Класс — это шаблон (форма) для создания объектов (экземпляров класса).

Класс и объект

Объекты (экземпляры класса)

Объект — это экземпляр класса, который обладает конкретным состоянием и поведением.

  • Состояние — это данные объекта, которые описывают его текущие характеристики (свойства, атрибуты). Состояние хранится в полях.
  • Поведение — это действия, которые объект может выполнять. Поведение определяется методами.

Если класс — это шаблон (форма), то объект — это то, что создано по этому шаблону (форме).

Структура класса

Класс состоит из объявления и тела. Класс объявляется с помощью ключевого слова class.

// Класс, экземпляры которого представляют прямоугольники

// Объявление класса
public class Rectangle {
    // Тело класса
}

Статический и нестатический контекст

Статический контекст:

  • Статический контекст включает поля и метода, принадлежащие классу.
  • Статические поля и методы определены для всех экземпляров классов одинаково.
  • Статические поля инициализируются при загрузке класса в JVM.

Нестатический контекст:

  • Нестатический контекст включает поля и метода, принадлежащие объекту (экземпляру класса).
  • Каждый объект имеет свою копию нестатических полей и методов.
  • Нестатические поля инициализируются при создании объекта.

Переменные экземпляра класса (нестатические поля)

Переменная экземпляра (нестатическое поле) — это переменная, объявленная непосредственно в теле класса; представляет некоторую характеристику объектов этого класса.

Объявление поля включает тип данных и имя.

public class Rectangle {
    // Координаты базовой точки (левого верхнего угла)
    int x, y;
    // Ширина и высота
    int width, height;
    // Цвет
    Color color;
}

Инициализация переменных экземпляра класса

Переменной экземпляра может быть присвоено начальное значение.

public class Rectangle {
    // Координаты базовой точки (левого верхнего угла)
    int x = 0, y = 0;
    // Ширина и высота
    int width = 100, height = 100;
    // Цвет
    Color color = Color.BLACK;
}

В случае, когда поле не инициализируется явно, ему автоматически присваивается значение по умолчанию в зависимости от его типа данных.

public class DefaultValuesExample {
    // ПРИМИТИВНЫЕ ТИПЫ
    byte defaultByte;        // 0
    short defaultShort;      // 0
    int defaultInt;          // 0
    long defaultLong;        // 0L
    float defaultFloat;      // 0.0f
    double defaultDouble;    // 0.0d
    char defaultChar;        // '\u0000' (нулевой символ)
    boolean defaultBoolean;  // false
    
    // ССЫЛОЧНЫЕ ТИПЫ
    String defaultString;    // null
    Object defaultObject;    // null
    int[] defaultArray;      // null
}

Локальные переменные НЕ инициализируются автоматически

Блоки инициализации экземпляра

Блоки инициализации экземпляра — это специальные блоки кода, которые выполняются при создании объекта.

public class Rectangle {
    // Переменные экземпляра
    int x, y; // Координаты базовой точки
    int width, height; // Ширина и высота    
    Color color; // Цвет
    
    // Блок инициализации экземпляра
    {
        x = 0; y = 0;
        color = Color.BLACK;
    }
}

Завершенные переменные экземпляра класса

Завершенные переменные экземпляра — это переменные экземпляра, которым не могут присваиваться никакие другие значения после их инициализации.

  • Объявляются с ключевым словом final
  • Должны инициализироваться только явным образом.
public class Rectangle {
    // Переменные экземпляра
    int x, y; // Текущие координаты базовой точки
    int width, height; // Ширина и высота    
    Color color; // Цвет
    
    // Завершенные переменные экземпляра
    final int startX = 0, startY = 0; // Начальные координаты базовой точки
}

Методы экземпляра класса

Метод экземпляра класса — это функция или процедура, объявленная в теле класса и определяющая алгоритм работы с объектами этого класса.

Метод состоит из объявления и тела. Объявление метода включает возвращаемый тип данных, имя и список параметров. В случае, когда метод ничего не возвращает, возвращаемый тип данных указывается ключевым словом void.

public class Rectangle {
    // Поля
    int x, y;
    int width, height;
    Color color = Color.BLACK;

    // Вычислить площадь
    int area() {
		    // Вернуть значение, соответсвующее возвращаемомум типу данных
        return width * height;
    }

    // Нарисовать прямоугольник в графическом контексте
    void draw(Graphics g) {
        g.setColor(color);
        g.fillRect(x, y, width, height);
    }

    // Передвинуть
    void move(int x, int y) {
        // Здесь происходит скрытие полей локальными переменными
        this.x = x;
        this.y = y;
    }

    // Масштабировать ширину и высоту пропорционально
    void scale(double factor) {
        if (factor > 0.0) {
            width *= factor;
            height *= factor;
        }
    }
}

Инструкция перехода return

return — это инструкция управления потоком выполнения, которая завершает выполнение метода и возвращает управление вызывающему коду.

Для методов с возвращаемым типом данных отличным от void инструкция return возвращает значение этого типа данных.

public class ReturnValueExample {
    // Метод с возвращаемым типом данных int
    public int add(int a, int b) {
        return a + b; // Возвращает значение примитивного типа int
    }
      
    public static void main(String[] args) {
        ReturnValueExample example = new ReturnValueExample();
        
        // Вызов метода экземпляра example.add
        // После возврата значения из метода example.add, 
        // переменной sum присваивается его значение
        int sum = example.add(5, 3);
        System.out.println("Sum: " + sum);
    }
}

Досрочное завершение void метода:

    // Void метод с явным return
    public void printIfPositive(int number) {
        if (number <= 0) {
            System.out.println("Number is not positive");
            return; // Досрочное завершение метода
        }
        
        System.out.println("Positive number: " + number);
        // return; // Неявный return в конце
    }

Передача параметров

Передача по значению для примитивных типов (передается копия значения):

public class PrimitiveParameters {
    
    // Метод получает КОПИЮ значения
    public static void modifyPrimitive(int number) {
        number = number * 2;  // изменяется копия
        System.out.println("Inside method: number = " + number);
    }
    
    public static void main(String[] args) {
        int original = 10;
        System.out.println("Before method: original = " + original);
        
        modifyPrimitive(original);  // передается копия значения
        
        System.out.println("After method: original = " + original);
    }
}

Передача по значению для ссылочных типов (передается копия ссылки):

public class ReferenceParameters {
    
    // Метод получает КОПИЮ ссылки на объект
    public static void modifyArray(int[] array) {
        array[0] = 100;  // изменяется содержимое объекта
        System.out.println("Inside method: array[0] = " + array[0]);
    }
    
    public static void changeReference(int[] array) {
        array = new int[]{999, 888, 777};  // изменяется копия ссылки
        System.out.println("Inside method: new array[0] = " + array[0]);
    }
    
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        
        System.out.println("Before modifyArray: numbers[0] = " + numbers[0]);
        modifyArray(numbers);
        System.out.println("After modifyArray: numbers[0] = " + numbers[0]);
        
        System.out.println("\nBefore changeReference: numbers[0] = " + numbers[0]);
        changeReference(numbers);
        System.out.println("After changeReference: numbers[0] = " + numbers[0]);
    }
}

Перегрузка методов

Перегрузка методов позволяет объявлять в одном классе несколько методов с одинаковыми именами, но разными списками параметров.

public class Rectangle {
    // Поля
    int x, y;
    int width, height;

    // Масштабировать ширину и высоту пропорционально
    void scale(double factor) {
        if (factor > 0.0) {
            width *= factor;
            height *= factor;
        }
    }

    // Масштабировать ширину и высоту раздельно
    void scale(double wFactor, double hFactor) {
        if (wFactor > 0.0)
            width *= wFactor;
        if (hFactor > 0.0)
            height *= hFactor;
    }
}

Переменное число аргументов

Переменное число аргументов (varargs) — это механизм, который позволяет методу принимать произвольное количество аргументов одного типа. Это альтернатива созданию перегруженных методов или передаче массива.

public class VarargsExample {
    
    // Метод с varargs
    public static int sum(int... numbers) {
        int total = 0;
        for (int num : numbers) {
            total += num;
        }
        return total;
    }
    
    public static void main(String[] args) {
        // Разные способы вызова
        System.out.println(sum());           // 0
        System.out.println(sum(1));          // 1
        System.out.println(sum(1, 2));       // 3
        System.out.println(sum(1, 2, 3, 4)); // 10
        
        // Можно передать массив
        int[] arr = {5, 6, 7};
        System.out.println(sum(arr));        // 18
    }
}

Компилятор преобразует varargs в массив:

// Если вы пишете:
public void method(String... strings)

// То компилятор преобразует этот код в:
public void method(String[] strings)

В методе может быть только один varargs-параметр и он должен быть последним:

public void method(String prefix, int... numbers)

Ключевое слово this

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

Ключевое слово this доступно только в нестатическом контексте.

public class Rectangle {
    // Поля
    int x, y;
    int width, height;

    // Вычислить площадь прямоугольника
    int area() {
        // Здесь ключевое слово this используется явно, 
        // хотя это не обязательно
        return this.width * this.height;
    }
}

Ключевое слово this необходимо использовать в случае скрытия полей локальными переменными.

public class Rectangle {
    // Поля
    int x, y; // Координаты базовой точки прямоугольника
    int width, height;

    // Переместить прямоугольник в точку с координатами x, y
    void move(int x, int y) {
        // Здесь поля x, y скрыты локальными переменными x, y,
        // поскольку имена параметров x, y совпадают с именами полей x, y
        this.x = x; // Обращение к полю x через this
        this.y = y; // Обращение к полю y через this
    }
}

Конструкторы

Конструкторы служат для создания объектов с заданным начальным состоянием. Имя конструктора должно совпадать с именем класса, в котором он объявлен.

public class Rectangle {
    // Поля
    int x, y;
    int width, height;
    Color color;

    // Конструктор
    Rectangle(int x, int y, int width, int height, Color color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
    }

    // Методы 
}

Порядок инициализации

Инициализация переменных экземпляра выполняется при его создании в следующем порядке:

  1. Поля экземпляра
  2. Блоки инициализации
  3. Конструкторы

Перегрузка конструкторов

В одном классе можно объявить несколько конструкторов с разными списками параметров.

public class Rectangle {
    // Поля
    int x, y;
    int width, height;
    Color color;

    // Конструкторы
    Rectangle(int x, int y, int width, int height, Color color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
    }

    Rectangle(int x, int y, int width, int height) {
        // Вызов перегруженного конструктора
        this(x, y, width, height, Color.BLACK);
    }

    Rectangle(int width, int height) {
        // Вызов перегруженного конструктора
        this(0, 0, width, height, Color.BLACK);
    }

    // Методы 
}

Создание объектов

Объекты класса создаются с помощью ключевого слова new, после которого следует вызов одного из доступных конструкторов.

public class MyMainClass {
    public static void main(String[] args) {
        Rectangle rect1 = new Rectangle(0,0, 100, 200);
        Rectangle rect2 = new Rectangle(100,200);
        Rectangle rect3 = new Rectangle(10,20, 100, 100, Color.RED);
    }
}

С объектами можно взаимодействовать через их доступные поля и методы.

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class MyMainClass {
    public static void main(String[] args) {
        // Создать прямоугольник
        Rectangle rect = new Rectangle(0,0, 400, 500);
        // Задать цвет
        rect.color = Color.RED;
        // Переместить прямоугольник
        rect.move(200, 300);
        // Уменьшить прямоугольник
        rect.scale(0.5);

        // Создать изображение и нарисовать на нем прямоугольник
        BufferedImage image = new BufferedImage(1000, 1000, 
                BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        rect.draw(g);
        try {
            File file = new File("image.png");
            ImageIO.write(image, "png", file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Задания

Задание 5-1 — 1 балл

  • Разработать класс верхнего уровня Rectangle в пакете ru.isu.math.graphics для представления прямоугольников. В классе должны быть определены нестатические поля (координаты базовой точки, ширины и высота ограничивающей рамки, угол поворота, цвет заливки и цвет контура), нестатические методы (перемещения, поворота и масштабирования эллипса, вычисления площади эллипса) и конструкторы. Должна быть перегрузка методов и конструкторов.
  • Разработать отдельный Main-класс в пакете ru.isu.math.graphics с main-методом, в котором необходимо создать несколько объектов класса Rectangle с помощью доступных конструкторов и через доступное поведение (перемещение, поворот, масштабирование) объектов класса Rectangle изменить их состояние. Вычислить площади созданных прямоугольников.
  • Продемонстрировать работу отладчика в IDE. Установить точку останова в вашем коде. Запустить отладчик. Показать какие значения имеют локальные переменные в момент останова. Сделать один или несколько шагов так, продемонстрировать изменение значений локальных переменных при пошаговом выполнении кода. Установить курсор в некоторой строке вашего кода и выполнить код до этой строки; показать какие значения имеют локальные переменные в этот момент. Возобновить выполнение программы в обычном режиме.

Задание 5-2 — 1 балл

  • Добавить класс верхнего уровня Ellipse в пакет ru.isu.math.graphics для представления эллипсов. В классе должны быть определены нестатические поля (координаты базовой точки, ширины и высота ограничивающей рамки, угол поворота, цвет заливки и цвет контура), нестатические методы (перемещения, поворота и масштабирования эллипса, вычисления площади эллипса) и конструкторы. Должна быть перегрузка методов и конструкторов.
  • Разработать отдельный Main-класс в пакете ru.isu.math.graphics с main-методом, в котором необходимо создать несколько объектов класса Rectangle и объектов класса Ellipse и нарисовать соответствующие им прямоугольники и эллипсы в файле изображения формата PNG.

Задание 5-3 — 2 балла

  • Разработать приложение с интерфейсом командной строки (CLI) для создания и управления простыми графическими фигурами с возможностью экспорта результата в растровое изображение.
  • Программа должна поддерживать создание двух типов фигур: прямоугольники (Rectangle) и эллипсы (Ellipse).
  • Программа должна позволять перемещать выбранной фигуры на заданное смещение по осям X и Y.
  • Программа должна позволять увеличивать или уменьшать размер существующей фигуры в заданное количество раз.
  • Программа должна сохранять все созданные фигуры в файл изображения в формате PNG.
  • Сопроводить исходный код Javadoc-комментариями и сгенерировать HTML-документацию с помощью команды javadoc.
  • Собрать проект в виде запускаемого JAR-файла и продемонстрировать его работу.

Поддерживаемые команды CLI:

  • Создание фигур
    • create rectangle <x> <y> <width> <height>
    • create ellipse <x> <y> <width> <height>
    • Пример: create rectangle 50 50 100 200 — создает прямоугольник с вершиной в (50,50), шириной 100 и высотой 200.
    • После создания фигура получает уникальный числовой идентификатор (ID). Этот ID используется для управления фигурой в последующих командах.
  • Перемещение фигур
    • move <id> <dx> <dy>
    • Пример: move 1 10 -5 — перемещает фигуру с ID=1 на 10 пикселей вправо и на 5 пикселей вверх.
  • Масштабирование фигур
    • scale <id> <factor>
    • Пример: scale 1 1.5 — увеличивает фигуру с ID=1 в 1.5 раза.
    • Пример: scale 2 0.5 — уменьшает фигуру с ID=2 в 2 раза.
  • Экспорт в изображение
    • export <filename.png>
    • Пример: export my_drawing.png — сохраняет изображение в файл my_drawing.png в текущей директории.
  • Прочие команды
    • list — выводит в консоль список всех фигур с их ID, типами и параметрами.
    • exit — завершает работу приложения.

Вопросы

  1. Объясните: как устроен ваш класс?
  2. Выделите фрагмент вашего код, соответствующий объявлению класса?
  3. Выделите фрагмент вашего код, соответствующий телу класса?
  4. Какие переменные экземпляра объявлены в вашем классе?
  5. Какие нестатические поля есть в вашем классе?
  6. Какие типы данных имеют переменные экземпляра в вашем классе?
  7. Как вы инициализировали переменные экземпляра?
  8. Какие нестатические методы есть в вашем классе?
  9. Выделите фрагмент вашего кода, соответствующий объявлению нестатического метода?
  10. Выделите фрагмент вашего кода, соответствующий телу нестатического метода?
  11. Используете ли вы перегрузку методов?
  12. Есть ли в вашем коде одноименные методы с различными сигнатурами?
  13. Какой список параметров имеет тот или иной метод?
  14. Какие типы данных имеют передаваемые в метод параметры?
  15. Какой возвращаемый тип данных имеет тот или иной метод?
  16. Куда передает управление инструкция перехода return в вашем коде?
  17. Какие конструкторы есть в ваше классе?
  18. Используете ли вы перегрузку конструкторов?
  19. Какую задачу выполняют ваши конструкторы?
  20. Какой список параметров имеет тот или иной конструктор?
  21. Есть ли у конструктора возвращаемый тип данных?
  22. Есть ли в вашем коде скрытие полей локальными переменными?
  23. Обращаетесь ли вы нестатическим полям через ключевое слово this?
  24. Как вы используете ключевое слово this при перегрузке конструкторов?
  25. Можно ли в вашем случае обойтись без ключевого слова this, если ДА, то как?
  26. Как вы создаете объекты вашего класса?
  27. Как вы объявляете переменные, значениями которых являются ссылки на объекты ваших классов?
  28. Что следует после оператора new в вашем коде?
  29. Как вы обращаетесь к полям объектов вашего класса?
  30. Как вы обращаетесь к методам объектов вашего класса?

Дополнительны ресурсы

  1. Object-Oriented Programming Concepts
  2. Java OOP