Іноді в Java зустрічається ситуація, коли потрібно успадкувати клас від декількох класів. Оскільки множинне спадкування класів в Java заборонено, цю проблему вирішують за допомогою внутрішніх класів: в потрібному нам класі ми оголошуємо внутрішній клас і успадковуємо його від необхідного класу. приклад:
Приклад внутрішнього класу, успадкованого від Thread |
---|
class Tiger extends Cat { public void tigerRun() { ..... } public void startTiger() { TigerThread thread = new TigerThread(); thread.start(); } class TigerThread extends Thread { public void run() { tigerRun(); } } } |
Нам потрібен клас, успадкований від Thread, щоб перевизначити у нього метод run. Для цього всередині класу Tiger ми оголосили внутрішньої клас TigerThread, який успадкували від Thread і у якого перевизначили метод run.
Для зручності в класі Tiger оголосили два методи (аналоги методів run і start класу Thread) -Методи tigerRun & startTiger. У методі startTiger створюємо об'єкт типу TigerThread і викликаємо у нього метод start (). При цьому Java-машина створить нову нитку, і ця нитка почне роботу з виклику методу run, класу TigerThread. А цей метод в свою чергу викличе метод run - метод tigerRun.
Чи обов'язково називати методи tigerRun і startTiger? Ні, можна було назвати run і start, але тут показано, що не успадковуємо від Thread.
Перепишемо код так:
Код |
---|
class Tiger extends Cat { public void tigerRun() { ..... } public void startTiger() { thread.start(); } private TigerThread thread = new TigerThread(); private class TigerThread extends Thread { public void run() { tigerRun(); } } } |
До | Після |
---|---|
TigerThread thread = new TigerThread(); private class TigerThread extends Thread { public void run() { tigerRun(); } } | Thread thread = new Thread() { public void run() { tigerRun(); } }; |
А) оголошення класу-спадкоємця
Б) перевизначення методу
В) оголошення змінної
Г) створення об'єкта класу-спадкоємця.
Фактично об'єднали разом дві операції - оголошення класу-спадкоємця і створення його об'єкта:
Без анонімного класу | З використанням анонімного класу |
---|---|
Cat tiger = new { } | Cat tiger = new Сat() { }; |
Оголошення змінної типу Thread |
---|
Thread thread = new Thread(); |
Оголошення змінної типу «анонімний клас-наслідник Thread» |
Thread thread = new Thread() { }; |
Якщо треба перевизначити метод run, то потрібно писати так:
Оголошення змінної типу Thread |
---|
Thread thread = new Thread() { public void run() { System.out.println("new run-method"); } }; |
Якщо потрібні ще методи, яких немає у класу Thread, то їх можна дописати. Це ж повноцінний внутрішній клас, хоч і анонімний:
Код | Опис |
---|---|
Thread thread = new Thread() { public void run() { printHi(); } public void printHi() { System.out.println("Hi!"); } }; | Червоним кольором відзначений код створення змінної. Зеленим - створення об'єкта. Синім - код анонімного класу-спадкоємця. |
Клас | Об'єкт анонімного внутрішнього класу |
---|---|
class Cat { int x, y; Cat(int x, int y) { this.x = x; thix.y = y; } } | Cat cat = new Cat(3,4) { public void print() { System.out.println(x+" "+y); } }; |
Не можна додати свої параметри в чужий конструктор. Зате можна використовувати змінні зовнішнього класу - це досить сильно компенсує цей недолік. А якщо все-таки дуже потрібно додати в конструктор ще параметри, тоді треба оголосити звичайний, а не анонімний внутрішній клас і використовувати його.
Коли оголосити статичну змінну, тоді анонімний клас все одно буде анонімним внутрішнім класом. Приклади:
З анонімним класом | Без анонімного класу |
---|---|
Thread thread = new Thread() { public void run() { tigerRun(); } }; | TigerThread thread = new TigerThread(); private class TigerThread extends Thread { public void run() { tigerRun(); } } |
static Thread thread = new Thread() { public void run() { tigerRun(); } }; | static TigerThread thread = new TigerThread(); private class TigerThread extends Thread { public void run() { tigerRun(); } } |
Насправді, в процесі компіляції Компілятор створює внутрішні класи для всіх анонімних внутрішніх класів. Такі класи зазвичай отримують імена «1», «2», «3», і т.д.