Конструкторы в 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. Лучшие практики при работе с конструкторами
- Минимизация логики в конструкторах
- Проверка параметров в начале конструктора
- Использование фабричных методов для сложной логики создания
- Документирование исключений, которые может бросить конструктор
- Избегание вызовов переопределяемых методов в конструкторе
- Обеспечение потокобезопасности при необходимости
- Правильная обработка ошибок и очистка ресурсов
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. Конструкторы/задание|задание]]