1. Локальний клас
Локальний клас — це клас, оголошений всередині методу (або навіть у блоці коду, наприклад, у циклі чи в блоці if). Він видимий і доступний лише в межах цього методу, а поза ним — ніби його й не було. На відміну від анонімних класів, локальний клас має імʼя (хоч і просте), може містити кілька методів і навіть поля.
Проведімо аналогію: уявіть, що ви готуєте складну страву за рецептом. На одному з кроків потрібно приготувати особливий соус, який використовують лише тут і більше ніде. Замість того щоб випускати окрему «книгу рецептів» заради одного соусу, ви описуєте його приготування безпосередньо всередині основного рецепта. Локальний клас працює так само — це «рецепт у рецепті», потрібен лише в одному конкретному методі.
Приклад оголошення локального класу
public class Outer {
void someMethod() {
class Local {
void print() {
System.out.println("Привіт від Local!");
}
}
Local local = new Local();
local.print();
}
}
Тут клас Local оголошено всередині методу someMethod класу Outer. Він існує лише в цьому методі й не видимий ззовні.
Синтаксис локальних класів
Оголошення локального класу схоже на звичне оголошення класу, лише відбувається всередині методу:
void myMethod() {
class MyLocalClass {
void doSomething() {
System.out.println("Локальний клас працює!");
}
}
MyLocalClass obj = new MyLocalClass();
obj.doSomething();
}
Особливості синтаксису:
- Локальний клас можна оголосити в будь-якому методі, конструкторі або навіть у блоці ініціалізації.
- Імʼя локального класу обовʼязкове (на відміну від анонімних класів).
- Локальний клас не можна оголошувати з модифікаторами доступу (public, private, protected) або з модифікатором static.
- Локальний клас може реалізовувати інтерфейси або успадковувати від інших класів.
Порівняння типів класів:
public class Example {
// 1. Звичайний клас (в окремому файлі)
// class RegularClass { ... }
// 2. Внутрішній клас (у класі)
class InnerClass { }
// 3. Статичний вкладений клас (у класі)
static class NestedClass { }
void method() {
// 4. Локальний клас (у методі)
class LocalClass { }
// 5. Анонімний клас (у методі, без імені)
Object obj = new Object() { };
}
}
Локальний клас — це іменований клас лише для цього методу!
2. Особливості локальних класів
Доступ до змінних методу
Локальний клас може звертатися до:
- полів зовнішнього класу (навіть якщо вони private);
- лише до змінних навколишнього методу, що є final або effectively final.
Що таке «effectively final»?
Це змінна, значення якої не змінюється після ініціалізації. Наприклад:
void foo() {
int x = 5; // effectively final
class L { void print() { System.out.println(x); } }
}
Якби ви пізніше написали x = 10;, компілятор видав би помилку.
Чому так?
Це пов’язано з тим, як Java реалізує локальні класи «під капотом»: змінні методу фактично копіюються всередину локального класу, а не зберігаються за посиланням. Якби змінна могла змінюватися, локальний клас працював би із застарілою копією — а це шлях до помилок і головного болю.
Приклад із доступом до змінних
public class Outer {
private String secret = "таємниця!";
void revealSecret() {
String greeting = "Привіт,"; // effectively final
class Revealer {
void printSecret() {
System.out.println(greeting + " " + secret);
}
}
Revealer revealer = new Revealer();
revealer.printSecret();
}
}
3. Застосування локальних класів: навіщо і коли?
Локальні класи — інструмент не на щодень, але іноді вони роблять код чистішим і компактнішим. Ось коли варто їх використовувати:
- Допоміжна логіка, специфічна для одного методу.
Наприклад, якщо в методі потрібно реалізувати складне сортування, фільтрацію або тимчасову структуру даних. - Інкапсуляція, щоб не «засмічувати» клас зайвими типами.
Якщо клас потрібен лише в одному місці, навіщо робити його видимим у всьому класі або пакеті? - Реалізація шаблонів проєктування, де допоміжні об’єкти потрібні тільки локально.
Приклад: сортування за допомогою локального класу
Припустімо, у вас є список імен, і ви хочете відсортувати їх за довжиною. Можна створити локальний клас-компаратор:
import java.util.*;
public class NameSorter {
public void sortNames(List<String> names) {
class LengthComparator implements Comparator<String> {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
}
Collections.sort(names, new LengthComparator());
}
}
Приклад: тимчасова структура
Іноді потрібно створити допоміжну структуру для обробки даних в одному методі:
void processScores(int[] scores) {
class ScoreInfo {
int score;
boolean passed;
ScoreInfo(int score) {
this.score = score;
this.passed = score >= 60;
}
}
for (int s : scores) {
ScoreInfo info = new ScoreInfo(s);
System.out.println("Оцінка: " + info.score + ", склав: " + info.passed);
}
}
4. Локальні класи vs. анонімні класи
Іноді виникає запитання: навіщо взагалі потрібні локальні класи, якщо є анонімні? Розберімося.
- Локальний клас — це іменований клас, який можна використовувати кілька разів у методі; до нього можна додати поля, кілька методів, вкладені класи.
- Анонімний клас — це разова реалізація інтерфейсу або класу-нащадка без імені, зазвичай з одним методом (або перевизначенням одного-двох методів).
Коли використовувати:
- Якщо логіка проста й потрібна лише один раз — використовуйте анонімний клас.
- Якщо потрібно більше методів або полів чи клас використовуватиметься в кількох місцях методу — використовуйте локальний клас.
Приклад порівняння
Анонімний клас:
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Швидко й анонімно!");
}
};
Локальний клас:
void doWork() {
class MyWorker implements Runnable {
@Override
public void run() {
System.out.println("Я локальний клас!");
}
}
MyWorker worker = new MyWorker();
worker.run();
}
5. Обмеження та особливості локальних класів
- Модифікатори доступу: локальний клас не можна оголосити як public, private або protected. Також не можна додати static.
- Статичні члени: локальний клас не може містити статичних членів, окрім констант (static final).
- Область видимості: локальний клас видимий лише в тому блоці, де його оголошено.
- Використання узагальнень: локальний клас може бути узагальненим, якщо це потрібно.
- Вкладеність: можна оголошувати локальні класи всередині інших локальних класів (але краще не зловживати цим, інакше код нагадуватиме ляльку-вкладанку).
6. Локальні класи в реальному застосунку
Продовжімо розвивати наш навчальний застосунок. Припустімо, у нас є клас Quiz, який ставить користувачеві запитання й перевіряє відповіді. Ми хочемо всередині методу перевірки створити тимчасовий клас, що зберігатиме відповідь користувача та статус перевірки.
Приклад: використання локального класу в застосунку
import java.util.Scanner;
public class Quiz {
private String question = "Столиця Франції?";
private String correctAnswer = "Париж";
public void runQuiz() {
Scanner scanner = new Scanner(System.in);
System.out.println(question);
String userAnswer = scanner.nextLine();
// Локальний клас для зберігання результату
class AnswerResult {
String answer;
boolean isCorrect;
AnswerResult(String answer) {
this.answer = answer;
this.isCorrect = answer.equalsIgnoreCase(correctAnswer);
}
void printResult() {
if (isCorrect) {
System.out.println("Правильно!");
} else {
System.out.println("Неправильно, правильна відповідь: " + correctAnswer);
}
}
}
AnswerResult result = new AnswerResult(userAnswer);
result.printResult();
}
}
Тут клас AnswerResult існує лише всередині методу runQuiz і більше ніде не потрібен. Це чудовий приклад локального класу на практиці!
7. Типові помилки під час роботи з локальними класами
Помилка № 1: спроба звернутися до змінної методу, яка не final або не effectively final.
Якщо ви оголосили змінну в методі, а потім змінили її значення після використання в локальному класі, компілятор одразу видасть помилку. Завжди стежте, щоб такі змінні не змінювалися після ініціалізації.
Помилка № 2: бажання додати модифікатори доступу або static.
Локальний клас не можна оголошувати з модифікаторами public, private, protected або static. Якщо ви спробуєте це зробити — компілятор не дозволить.
Помилка № 3: спроба використовувати локальний клас поза методом.
Локальний клас живе лише в тому методі (або блоці), де його оголошено. З інших методів або ззовні класу він недоступний.
Помилка № 4: зловживання локальними класами для складної логіки.
Якщо ваш локальний клас стає надто великим, містить багато методів або полів, найімовірніше, його варто винести в окремий клас. Локальні класи доречні для компактних, допоміжних завдань.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ