Назад Зміст Вперед

11.5 Множинне наслідування

Іноді в 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 Tiger();

class Tiger extends Cat
{
}
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», і т.д.





















.