Внутренние и вложенные классы

Последнее обновление: 03.10.20125

В языке Java классы могут быть вложенными (nested), то есть могут быть определены внутри других классов. Все вложенные классы подразделяются на два типа: внутренние классы (вложенные нестатические классы) и вложенные статические классы.

Внутренние классы

Внутренние классы (inner class) являются частным случаем вложенных классов. Использование внутренних классов преследует главным образом две цели:

  • Внутренние классы могут быть скрыты от других классов в том же пакете.

  • Методам внутреннего класса доступны данные, в том числе и приватные, из внешней области видимости (из внешнего класса).

Например, имеется класс Person, внутри которого определен класс Account:

public class Program{
      
    public static void main(String[] args) {
             
        Person tom = new Person("Tom", "qwerty");
        tom.print();
        tom.account.print();
    }
}
class Person{
     
    private String name;
    Account account;
 
    Person(String name, String password){
        this.name = name;
        account = new Account(password);
    }
    void print(){
        System.out.printf("Person \t Name: %s \t Password: %s \n", name, account.password);
    }
 
    public class Account{
        private String password;
         
        Account(String pass){ this.password = pass; }

        void print(){
            System.out.printf("Account Login: %s \t Password: %s \n", Person.this.name, password);
        }
    }
}

Отмечу ключевые моменты программы:

  • Внутренний класс ведет себя как обычный класс за тем исключением, что его объекты могут быть созданы только внутри внешнего класса.

  • Внутренний класс имеет доступ ко всем полям внешнего класса, в том числе закрытым с помощью модификатора private. Аналогично внешний класс имеет доступ ко всем компонентам внутреннего класса, в том числе к полям и методам с модификатором private.

  • Ссылку на объект внешнего класса из внутреннего класса можно получить с помощью выражения Внешний_класс.this, например, Person.this.

  • Объекты внутренних классов могут быть созданы только в том классе, в котором внутренние классы опеределены. В других внешних классах объекты внутреннего класса создать нельзя.

Локальные внутренние классы

Еще одной особенностью внутренних классов является то, что их можно объявить внутри любого контекста, в том числе внутри метода и даже в цикле. Мотивация для использования таких классов состоит в том, что их объекты могут быть необходимы только в каком-то определенном контексте, например, в каком-то определенном методе, и больше нигде.

Локальные классы никогда не объявляются со спецификатором доступа, а их область действия всегда ограничена блоком, в котором они объявлены. При этом локальные классы полностью скрыты от внешнего мира - к ним можно обратиться только из контекста, в котором они определены. Например:

public class Program{
     
	public static void main(String[] args) {

        Person tom = new Person("Tom");
        tom.setTempAccount("qwerty");
	}
}


class Person{
	
	private String name;

	Person(String name){ this.name = name; }
	
	void setTempAccount (String password){
		
		class TempAccount{
			
			private void print(){
				System.out.printf("Account Login: %s \t Password: %s \n", name, password);
			}
		}
		TempAccount account = new TempAccount();
		account.print();
	}
}

В данном случае класс TempAccount и его объекты доступны только в рамках метода setTempAccount. ПРи этом в данном методе мы можем обращаться том числе и к приватным компонентам объекта: здесь я специально сделал метод print() приватным, но тем не менее мы можем его вызвать из метода setTempAccount.

Статические вложенные классы

Кроме внутренних классов внутри других классов также можно определять статические вложенные классы (nested static class). Статический вложенный класс похож на внутренний класс, за исключением того, что объект статического класса не имеет ссылки на объект внешнего класса. Статические вложенные классы позволяют скрыть некоторую комплексную информацию внутри внешнего класса:

class Math{

    public static class Factorial{
    
        private int result;
        private int key;
        
        public Factorial(int number, int x){
            
            result=number;
            key = x;
        }
        
        public int getResult(){
            return result;
        }
        
        public int getKey(){
            return key;
        }
    }
    
    public static Factorial getFactorial(int x){
    
        int result=1;
        for (int i = 1; i <= x; i++){
		
            result *= i;
        }
        return new Factorial(result, x);
    }
}

Здесь определен вложенный класс для хранения данных о вычислении факториала. Основные действия выполняет метод getFactorial, который возвращает объект вложенного класса. И теперь используем классы в методе main:

public static void main(String[] args) {
        
    Math.Factorial fact = Math.getFactorial(6);
    System.out.printf("Факториал числа %d равен %d \n", fact.getKey(), fact.getResult());
} 
Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850