Skip to content

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

1. Введение

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

2. Основные характеристики конструкторов

  • Имя конструктора должно совпадать с именем класса
  • Конструктор не имеет возвращаемого типа (даже void)
  • Конструктор вызывается автоматически при создании объекта
  • В классе может быть несколько конструкторов (перегрузка)

3. Виды конструкторов

3.1 Конструктор по умолчанию

public class SimpleClass {
    // Конструктор по умолчанию создается автоматически, если нет других конструкторов
    public SimpleClass() {
        // пустое тело
    }
}

3.2 Параметризованный конструктор

public class Student {
    private String name;
    private int age;

    // Параметризованный конструктор
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

3.3 Конструктор копирования

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Конструктор копирования
    public Person(Person other) {
        this.name = other.name;
        this.age = other.age;
    }
}

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

public class Book {
    private String title;
    private String author;
    private int pages;
    private String isbn;

    // Конструктор с всеми параметрами
    public Book(String title, String author, int pages, String isbn) {
        this.title = title;
        this.author = author;
        this.pages = pages;
        this.isbn = isbn;
    }

    // Конструктор с частичными параметрами
    public Book(String title, String author) {
        this(title, author, 0, "Unknown");
    }

    // Конструктор по умолчанию
    public Book() {
        this("Unknown", "Unknown", 0, "Unknown");
    }
}

5. Цепочка вызовов конструкторов

5.1 Использование this()

public class Employee {
    private String name;
    private String position;
    private double salary;

    public Employee(String name, String position, double salary) {
        this.name = name;
        this.position = position;
        this.salary = salary;
    }

    public Employee(String name, String position) {
        this(name, position, 50000.0); // Вызов другого конструктора
    }

    public Employee(String name) {
        this(name, "Junior"); // Цепочка вызовов
    }
}

6. Инициализационные блоки

public class ComplexClass {
    private int[] numbers;
    private String name;

    // Статический блок инициализации
    static {
        System.out.println("Статическая инициализация");
        // Выполняется один раз при загрузке класса
    }

    // Нестатический блок инициализации
    {
        System.out.println("Блок инициализации");
        numbers = new int[10];
        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = i * 2;
        }
    }

    public ComplexClass() {
        name = "Default";
    }

    public ComplexClass(String name) {
        this.name = name;
    }
}

7. Конструкторы и наследование

class Animal {
    protected String name;
    protected int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Dog extends Animal {
    private String breed;

    public Dog(String name, int age, String breed) {
        super(name, age); // Вызов конструктора родительского класса
        this.breed = breed;
    }
}

8. Приватные конструкторы

public class Singleton {
    private static Singleton instance;

    // Приватный конструктор
    private Singleton() {
        // инициализация
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

9. Конструкторы и исключения

public class BankAccount {
    private String accountNumber;
    private double balance;

    public BankAccount(String accountNumber, double initialBalance) 
            throws IllegalArgumentException {
        if (accountNumber == null || accountNumber.length() < 5) {
            throw new IllegalArgumentException("Неверный номер счета");
        }
        if (initialBalance < 0) {
            throw new IllegalArgumentException("Начальный баланс не может быть отрицательным");
        }

        this.accountNumber = accountNumber;
        this.balance = initialBalance;
    }
}

10. Примеры сложных конструкторов

10.1 Построитель объектов (Builder Pattern)

public class Computer {
    private String processor;
    private int ram;
    private int storage;
    private String graphicsCard;

    private Computer(ComputerBuilder builder) {
        this.processor = builder.processor;
        this.ram = builder.ram;
        this.storage = builder.storage;
        this.graphicsCard = builder.graphicsCard;
    }

    public static class ComputerBuilder {
        private String processor;
        private int ram;
        private int storage;
        private String graphicsCard;

        public ComputerBuilder(String processor) {
            this.processor = processor;
        }

        public ComputerBuilder withRam(int ram) {
            this.ram = ram;
            return this;
        }

        public ComputerBuilder withStorage(int storage) {
            this.storage = storage;
            return this;
        }

        public ComputerBuilder withGraphicsCard(String graphicsCard) {
            this.graphicsCard = graphicsCard;
            return this;
        }

        public Computer build() {
            return new Computer(this);
        }
    }
}

// Использование:
Computer computer = new Computer.ComputerBuilder("Intel i7")
    .withRam(16)
    .withStorage(512)
    .withGraphicsCard("NVIDIA RTX 3080")
    .build();

10.2 Фабричные методы

public class DatabaseConnection {
    private String url;
    private String username;
    private String password;

    private DatabaseConnection(String url, String username, String password) {
        this.url = url;
        this.username = username;
        this.password = password;
    }

    // Фабричные методы вместо конструкторов
    public static DatabaseConnection createMySQLConnection(String database) {
        return new DatabaseConnection(
            "jdbc:mysql://localhost/" + database,
            "root",
            "password"
        );
    }

    public static DatabaseConnection createPostgresConnection(String database) {
        return new DatabaseConnection(
            "jdbc:postgresql://localhost/" + database,
            "postgres",
            "password"
        );
    }
}

11. Практические примеры и задачи

11.1 Создание иммутабельного класса

public final class ImmutablePerson {
    private final String name;
    private final int age;
    private final List<String> hobbies;

    public ImmutablePerson(String name, int age, List<String> hobbies) {
        this.name = name;
        this.age = age;
        // Создаем копию списка для обеспечения иммутабельности
        this.hobbies = new ArrayList<>(hobbies);
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public List<String> getHobbies() {
        // Возвращаем копию списка
        return new ArrayList<>(hobbies);
    }
}

11.2 Конструктор с валидацией

public class EmailMessage {
    private String from;
    private String to;
    private String subject;
    private String body;

    public EmailMessage(String from, String to, String subject, String body) {
        validateEmail(from);
        validateEmail(to);
        validateSubject(subject);

        this.from = from;
        this.to = to;
        this.subject = subject;
        this.body = body != null ? body : "";
    }

    private void validateEmail(String email) {
        if (email == null || !email.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
            throw new IllegalArgumentException("Неверный email адрес: " + email);
        }
    }

    private void validateSubject(String subject) {
        if (subject == null || subject.trim().isEmpty()) {
            throw new IllegalArgumentException("Тема не может быть пустой");
        }
    }
}

12. Специальные случаи использования конструкторов

12.1 Конструкторы в Enum

public enum Planet {
    MERCURY(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6);

    private final double mass;   // в килограммах
    private final double radius; // в метрах

    // Конструктор для enum
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }

    public double getMass() {
        return mass;
    }

    public double getRadius() {
        return radius;
    }

    // Вычисление гравитации
    public double surfaceGravity() {
        double G = 6.67300E-11;
        return G * mass / (radius * radius);
    }
}

12.2 Конструкторы во внутренних классах

public class OuterClass {
    private int value;

    public OuterClass(int value) {
        this.value = value;
    }

    public class InnerClass {
        private int innerValue;

        public InnerClass(int innerValue) {
            this.innerValue = innerValue;
        }

        public void printValues() {
            System.out.println("Outer value: " + value);
            System.out.println("Inner value: " + innerValue);
        }
    }

    public static class StaticNestedClass {
        private int nestedValue;

        public StaticNestedClass(int nestedValue) {
            this.nestedValue = nestedValue;
        }
    }
}

// Использование:
OuterClass outer = new OuterClass(10);
OuterClass.InnerClass inner = outer.new InnerClass(20);
OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass(30);

13. Конструкторы и многопоточность

13.1 Потокобезопасный конструктор

public class ThreadSafeClass {
    private final List<String> list;
    private final Map<String, Integer> map;
    private volatile int count;

    public ThreadSafeClass() {
        // Использование потокобезопасных коллекций
        this.list = Collections.synchronizedList(new ArrayList<>());
        this.map = new ConcurrentHashMap<>();
        this.count = 0;
    }

    public ThreadSafeClass(Collection<String> initialData) {
        this(); // Вызов основного конструктора

        // Безопасное добавление начальных данных
        synchronized (list) {
            list.addAll(initialData);
            count = initialData.size();
        }
    }
}

13.2 Конструктор с отложенной инициализацией

public class LazyInitClass {
    private static class ResourceHolder {
        private static final ExpensiveResource resource = new ExpensiveResource();
    }

    private ExpensiveResource resource;

    public LazyInitClass() {
        // Конструктор не инициализирует ресурс
    }

    public ExpensiveResource getResource() {
        if (resource == null) {
            resource = ResourceHolder.resource;
        }
        return resource;
    }
}

14. Примеры сложных сценариев инициализации

14.1 Конструктор с несколькими этапами инициализации

public class DatabaseManager {
    private Connection connection;
    private Properties config;
    private List<String> tables;

    public DatabaseManager() {
        try {
            // Этап 1: Загрузка конфигурации
            loadConfiguration();

            // Этап 2: Установка соединения
            establishConnection();

            // Этап 3: Инициализация метаданных
            initializeTables();

        } catch (Exception e) {
            cleanup();
            throw new RuntimeException("Failed to initialize DatabaseManager", e);
        }
    }

    private void loadConfiguration() throws IOException {
        config = new Properties();
        try (InputStream input = getClass().getResourceAsStream("/db.properties")) {
            config.load(input);
        }
    }

    private void establishConnection() throws SQLException {
        String url = config.getProperty("db.url");
        String username = config.getProperty("db.username");
        String password = config.getProperty("db.password");

        connection = DriverManager.getConnection(url, username, password);
    }

    private void initializeTables() throws SQLException {
        tables = new ArrayList<>();
        try (ResultSet rs = connection.getMetaData().getTables(null, null, "%", null)) {
            while (rs.next()) {
                tables.add(rs.getString("TABLE_NAME"));
            }
        }
    }

    private void cleanup() {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                // логирование ошибки
            }
        }
    }
}

14.2 Конструктор с условной инициализацией

public class ConfigurableService {
    private final ServiceMode mode;
    private final ExecutorService executor;
    private final Cache cache;

    public ConfigurableService(ServiceConfig config) {
        // Определение режима работы
        this.mode = determineServiceMode(config);

        // Условная инициализация компонентов
        this.executor = initializeExecutor(config, mode);
        this.cache = initializeCache(config, mode);

        // Пост-инициализация
        if (mode == ServiceMode.HIGH_PERFORMANCE) {
            warmupCache();
        }
    }

    private ServiceMode determineServiceMode(ServiceConfig config) {
        if (config.isHighPerformance()) {
            return ServiceMode.HIGH_PERFORMANCE;
        } else if (config.isLowMemory()) {
            return ServiceMode.LOW_MEMORY;
        }
        return ServiceMode.NORMAL;
    }

    private ExecutorService initializeExecutor(ServiceConfig config, ServiceMode mode) {
        int threads = switch (mode) {
            case HIGH_PERFORMANCE -> Runtime.getRuntime().availableProcessors() * 2;
            case LOW_MEMORY -> 2;
            case NORMAL -> Runtime.getRuntime().availableProcessors();
        };

        return Executors.newFixedThreadPool(threads);
    }

    private Cache initializeCache(ServiceConfig config, ServiceMode mode) {
        return switch (mode) {
            case HIGH_PERFORMANCE -> new LargeCache(config.getCacheSize());
            case LOW_MEMORY -> new SmallCache();
            case NORMAL -> new DefaultCache();
        };
    }

    private void warmupCache() {
        // Предварительное заполнение кэша
    }

    private enum ServiceMode {
        HIGH_PERFORMANCE,
        NORMAL,
        LOW_MEMORY
    }
}

15. Лучшие практики при работе с конструкторами

  1. Минимизация логики в конструкторах
  2. Проверка параметров в начале конструктора
  3. Использование фабричных методов для сложной логики создания
  4. Документирование исключений, которые может бросить конструктор
  5. Избегание вызовов переопределяемых методов в конструкторе
  6. Обеспечение потокобезопасности при необходимости
  7. Правильная обработка ошибок и очистка ресурсов
public class BestPracticesExample {
    private final String name;
    private final int value;
    private final List<String> items;

    /**
     * Создает новый экземпляр с указанными параметрами.
     *
     * @param name  имя объекта (не может быть null)
     * @param value значение (должно быть положительным)
     * @param items список элементов (не может быть null)
     * @throws IllegalArgumentException если параметры недопустимы
     */
    public BestPracticesExample(String name, int value, List<String> items) {
        // 1. Проверка параметров
        validateConstructorParameters(name, value, items);

        // 2. Инициализация полей
        this.name = name;
        this.value = value;
        this.items = new ArrayList<>(items); // Защитное копирование

        // 3. Базовая инициализация завершена

        // 4. Дополнительная инициализация (если необходима)
        try {
            initialize();
        } catch (Exception e) {
            throw new IllegalStateException("Failed to initialize object", e);
        }
    }

    private void validateConstructorParameters(String name, int value, List<String> items) {
        if (name == null) {
            throw new IllegalArgumentException("Name cannot be null");
        }
        if (value <= 0) {
            throw new IllegalArgumentException("Value must be positive");
        }
        if (items == null) {
            throw new IllegalArgumentException("Items list cannot be null");
        }
    }

    private void initialize() {
        // Дополнительная инициализация
    }
}

пример

[[Programming/java/1. osnovi/Тема 4. Наследование/Урок 2. Конструкторы/задание|задание]]