В языке Java определены вложенные классы. Вложенным называется такой класс, который объявляется в другом классе.
Вложенные классы не относятся к базовым языковым средствам Java. Они даже не поддерживались до появления версии Java 1.1, хотя с тех пор часто применяются в реальных программах, и поэтому о них нужно знать.
Вложенный класс не может существовать независимо от класса, в который он вложен. Следовательно, область действия вложенного класса ограничена его внешним классом. Если вложенный класс объявлен в пределах области действия внешнего класса, то он становится членом последнего. Имеется также возможность объявить вложенный класс, который станет локальным в пределах блока.
Существуют два типа вложенных классов. Одни вложенные классы объявляются с помощью модификатора доступа static, а другие — без него. Классы такого типа называются внутренними. Внутренний класс имеет доступ ко всем переменным и методам внешнего класса, в который он вложен, и может обращаться к ним непосредственно, как и все остальные нестатические члены внешнего класса.
Иногда внутренний класс используется для предоставления ряда услуг внешнему классу, в котором он содержится. Ниже приведен пример применения внутреннего класса для вычисления различных значений, которые используются включающим его классом.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
// Применение внутреннеого класса class Outer { int nums[]; Outer(int n[]) { nums = n; } void Analyze() { Inner inOb = new Inner(); System.out.println("Минимум: " + inOb.min()); System.out.println("Максимум: " + inOb.max()); System.out.println("Среднее: " + inOb.avg()); } // Внутренний класс class Inner { int min() { int m = nums[0]; for(int i = 1; i < nums.length; i++) { if(nums[i] < m) m = nums[i]; } return m; } int max() { int m = nums[0]; for(int i = 1; i < nums.length; i++) { if(nums[i] > m) m = nums[i]; } return m; } int avg() { int a = 0; for(int i = 1; i < nums.length; i++) { a += nums[i]; } return a / nums.length; } } } class NestedClassDemo { public static void main(String args[]) { int x[] = {1, 2, 3, 5, 6, 7, 8, 9}; Outer outOb = new Outer(x); outOb.Analyze(); } } |
Результат выполнения данной программы выглядит следующим образом.
1 2 3 |
Минимум: 1 Максимум: 9 Среднее: 5 |
В данном примере внутренний класс Inner обрабатывает массив nums, являющийся членом класса Outer.
Вложенный класс имеет доступ к членам объемлющего класса, и поэтому он может непосредственно обращаться к массиву nums. А вот обратное несправедливо. Так, например, метод Analyze() не может непосредственно вызвать метод min() , не создав объект типа Inner.
Класс можно вложить в области действия блока. В итоге получается локальный класс, недоступный за пределами блока. В следующем примере программы мы преобразуем класс ShowBits, таким образом, чтобы он стал локальным.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// Применение класса ShowBits в качестве локальнго класса class LocalClassDemo { public static void main(String args[]) { // Внутренняя версия класса ShowBits // Локальный класс, вложенный в главном методе main class ShowBits { int numbits; ShowBits(int n) { numbits = n; } void show(long val) { long mask = 1; // Сдвиг влево для установки единицы в нужно позиции mask <<= numbits - 1; int spacer = 0; for(; mask != 0; mask >>>=1) { if((val & mask) != 0) System.out.print("1"); else System.out.print("0"); spacer++; if((spacer % 8) == 0) { System.out.print(" "); spacer = 0; } } System.out.println(); } } for(byte b = 0; b < 10; b++) { ShowBits byteval = new ShowBits(8); System.out.print(b + " в двоичном представлении: "); byteval.show(b); } } } |
Выполнение этой программы дает следующий результат.
1 2 3 4 5 6 7 8 9 10 |
0 в двоичном представлении: 00000000 1 в двоичном представлении: 00000001 2 в двоичном представлении: 00000010 3 в двоичном представлении: 00000011 4 в двоичном представлении: 00000100 5 в двоичном представлении: 00000101 6 в двоичном представлении: 00000110 7 в двоичном представлении: 00000111 8 в двоичном представлении: 00001000 9 в двоичном представлении: 00001001 |
В данном примере класс ShowBits недоступен за пределами метода main(), а следовательно, попытка получить доступ к нему из любого метода, кроме main(), приведет к ошибке.
И последнее замечание: внутренний класс может быть безымянным. Экземпляр безымянного, или анонимного, внутреннего класса создается при объявлении класса с помощью оператора new.
Чем же статический вложенный класс отличается от нестатического в языке программирования Java?
Статический вложенный класс объявляется с помощью модификатора static. Являясь статическим, он может непосредственно обращаться к любому статическому члену своего внешнего класса. Другие члены внешнего класса доступны ему посредством ссылки на объект.