← Назад к вопросам

Для чего нужен package private?

1.0 Junior🔥 161 комментариев
#ООП

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Для чего нужен package private?

Package private (отсутствие модификатора доступа, или default access) — это модификатор видимости, который ограничивает доступ к членам класса только классами в одном пакете.

Что такое package private

Это когда ты НЕ пишешь никакой модификатор (ни public, ни private, ни protected):

// Package private класс
class UserRepository {  // НЕ public!
    void save(User user) { }
}

// Package private метод
public class UserService {
    String getPassword(User user) {  // НЕ public!
        return user.password;
    }
}

Модификаторы доступа в Java

МодификаторТот же классТот же пакетПодкласс (другой пакет)Все
private
package-private (default)
protected
public

Пример структуры проекта

com.example.users/
├── UserService.java (public класс)
└── UserRepository.java (package-private класс)

com.example.orders/
├── OrderService.java
└── OrderRepository.java

Видимость между пакетами

// В пакете com.example.users
public class UserService {
    public User getUser(int id) { }
}

class UserRepository {  // Package-private!
    void save(User user) { }
}

// В пакете com.example.orders
public class OrderService {
    public void createOrder(int userId) {
        UserService service = new UserService(); // OK (public класс)
        service.getUser(userId);                 // OK (public метод)
        
        UserRepository repo = new UserRepository(); // ОШИБКА!
        // Не видна за пределами пакета com.example.users
    }
}

Для чего нужен package-private

1. Скрыть внутренние детали реализации

// Пакет com.example.auth

// Public API
public class AuthService {
    public boolean validateToken(String token) {
        return TokenValidator.validate(token);
    }
}

// Внутренний вспомогательный класс
class TokenValidator {  // Package-private!
    static boolean validate(String token) {
        // Сложная логика валидации
    }
}

// Внешний код может использовать AuthService,
// но НЕ может напрямую вызвать TokenValidator

2. Контроль над архитектурой пакета

// Правильная архитектура:
// UserService (PUBLIC) — фасад
//   ├─ UserRepository (package-private) — данные
//   ├─ UserValidator (package-private) — валидация
//   └─ UserMapper (package-private) — преобразование

public package com.example.users;

// API
public class UserService {
    private UserRepository repository;
    private UserValidator validator;
    private UserMapper mapper;
    
    public User createUser(CreateUserRequest request) {
        validator.validate(request);     // Используем внутренний класс
        User user = mapper.toEntity(request);
        repository.save(user);           // Используем внутренний класс
        return user;
    }
}

// Внутренние детали
class UserRepository { }
class UserValidator { }
class UserMapper { }

// Снаружи пакета видна только UserService!

3. Предотвращение неправильного использования

// Пакет com.example.database

// Клиенты должны использовать сервисы, не Connection напрямую
public class DatabaseService {
    public User getUser(int id) {
        Connection conn = getConnection();  // Package-private метод
        // ...
    }
}

// Это скрыто и недоступно извне пакета
class DatabaseConnectionPool { }
class DatabaseConfig { }

Реальный пример: Spring Framework

// В org.springframework.context

// PUBLIC API
public class ClassPathXmlApplicationContext implements ApplicationContext {
    public ClassPathXmlApplicationContext(String configLocation) {
        // ...
    }
}

// ВНУТРЕННИЕ детали (package-private)
class XmlBeanDefinitionReader { }
class BeanDefinitionParser { }
class ResourceLoader { }

// Клиенты используют ClassPathXmlApplicationContext,
// но не видят внутренней реализации

Лучшие практики

1. Минимизируй public, максимизируй package-private

// Плохо: слишком много public
public class User {
    public String name;                    // public
    public void setName(String n) { }      // public
    public void validateName() { }         // public
    public boolean isNameValid() { }       // public
}

// Хорошо: скрываем детали
public class User {
    private String name;                   // private
    public void setName(String n) {        // public (нужно снаружи)
        if (isNameValid(n)) {
            this.name = n;
        }
    }
    private boolean isNameValid(String n) { }  // package-private (вспомогательный)
}

2. Используй package-private для helper классов

// Пакет com.example.payment

// Main API
public class PaymentService {
    public PaymentResult process(PaymentRequest request) {
        validator.validate(request);
        processor.process(request);
    }
}

// Helper классы
class PaymentValidator {  // Package-private
    void validate(PaymentRequest request) { }
}

class PaymentProcessor {  // Package-private
    void process(PaymentRequest request) { }
}

3. Package-private для тестирования

// Production код
public class UserService {
    private UserRepository repository;
    
    // Package-private для тестирования
    UserRepository getRepository() {
        return repository;
    }
}

// Тесты в том же пакете
public class UserServiceTest {
    void testRepository() {
        UserService service = new UserService();
        UserRepository repo = service.getRepository();  // OK!
    }
}

Иерархия видимости (от самого видимого к самому скрытому)

public
   ↓
protected (только для наследников)
   ↓
package-private (только в пакете)
   ↓
private (только в классе)

Когда используется в реальных проектах

Spring Boot — много package-private компонентов ✓ Google Guava — скрывает внутреннюю реализацию ✓ Apache Commons — использует package-private для helper классов ✓ JDK — java.lang.* содержит множество package-private классов

Вывод

Package-private нужен для:

  1. Скрытия внутренней реализации — клиенты видят только публичный API

  2. Контроля архитектуры — предотвращаешь неправильное использование классов

  3. Упрощения рефакторинга — можешь менять внутренние классы без нарушения API

  4. Предотвращения dependency chains — клиенты не зависят от внутренних деталей

  5. Улучшения безопасности — скрываешь конфиденциальные детали реализации

Правило 80/20: В хорошем проекте ~20% классов public, остальные 80% package-private или private.

Для чего нужен package private? | PrepBro