Анонимные классы

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

Иногда бывает необходимо создать только один объект некоторого класса. Причем его имя даже не важно. Такой класс можно определить как анонимный. Часто анонимные классы создаются там, где требуется объект некоторого интерфейс, чтобы не определять отдельный класс.

Общий синтаксис определения анонимного класса следующий:

new SuperType(аргументы для конструктора суперкласса)
{
    // поля и методы анонимного класса
}

Здесь SuperType может быть интерфейсом, тогда анонимный класс реализует этот интерфейс. SuperType также может быть классом, тогда анонимный класс расширяет этот класс.

Анонимный внутренний класс не может иметь конструкторов, поскольку имя конструктора должно совпадать с именем класса, а у класса нет имени. Вместо этого аргументы конструирования передаются конструктору суперкласса (если в суперклассе определен конструктор с параметрами).

Если SuperType представляет интерфейс, то аргументы для конструктора естественно не передаются (ведь у интерфейсов нет конструктора), и просто указываются аустые скобки:

new InterfaceType()
{
    // поля и методы анонимного класса
}

Анонимный класс вместо интерфейса

Распространенным вариантом использования анонимных классов является их создание там, где требуется объект интерфейса. Например:

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

        var rectangle = new Movable(){

            public void move(int distance){
                System.out.printf("Перемещаем прямоугольник на %d пикселей\n", distance);
            }
        };
        moveObject(rectangle, 56);     // Перемещаем прямоугольник на 56 пикселей
	}
    // перемещаем объект Movable на расстояние distance
    static void moveObject(Movable obj, int distance){
        obj.move(distance);
    }
}

interface Movable{
    void move(int distance);
}

Основные моменты:

  1. У нас есть интерфейс Movable, в котором определен метод move()

    interface Movable{
        void move(int distance);
    }
    
  2. Определяем метод moveObject(), в который передается объект интерфейса Movable. И далее у этого объекта вызывается метод move()

    static void moveObject(Movable obj, int distance){
        obj.move(distance);
    }
    
  3. Определяем переменную rectangle, которая по сути представляет объект анонимного класса, который, в свою очередь, реализует интерфейс Movable:

    var rectangle = new Movable(){
    
        public void move(int distance){
            System.out.printf("Перемещаем прямоугольник на %d пикселей\n", distance);
        }
    };
    

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

  4. И в конце вызываем метод moveObject(), передавая в него объект анонимного класса:

    moveObject(rectangle, 54);

При этом нам необязательно создавать отдельно переменную, которая содержит ссылку на объект анонимного класса. Мы можем создать объект анонимного класса непосредственно при вызове метода:

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

        // передаем объект анонимного класса
        moveObject(new Movable(){
            public void move(int distance){
                System.out.printf("Человек идет на расстояние %d метров\n", distance);
            }
        }, 
        100);
	}
    static void moveObject(Movable obj, int distance){
        obj.move(distance);
    }
}

interface Movable{
    void move(int distance);
}

Анонимный класс вместо класса

Менее распространенный вариант, но тем не менее возможный - это расширение анонимным классом обычного класса. Например:

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

        printPerson(
            new Person("Tom"){

                private String company = "Yandex";

                // реализация метода print
                @Override
                void print(){
                    System.out.printf("Employee. Name: %s;  Company: %s\n", super.getName(), company);
                }
            }
        );
	}
    static void printPerson(Person person){
        person.print();
    }
}
abstract class Person{
    
    private String name;
    String getName(){ return name;}

    Person(String name){

        this.name = name;
    }

    abstract void print();
}

Рассмотрим основные моменты:

  1. Здесь определен абстрактный класс Person, который представляет некоторого человека. Через конструктор он принимает имя и определяет абстрактный метод ptint()

  2. Статический метод printPerson() принимает объект Person и вызывает у него метод ptint()

    static void printPerson(Person person){
        person.print();
    }
    
  3. При вызове метода printPerson() передаем объект анонимного класса. Причем, как мы знаем, в Java мы не можем использовать вызов конструктора для создания объекта абстрактного класса. И в данном случае вызов

    new Person("Tom")

    означает создание объекта анонимного класса, который расширяет класс Person и передает в его конструктор строку "Tom".

    Затем в фигурных скобках определяем тело анонимного класса:

    {
        private String company = "Yandex";
        @Override
        void print(){
            System.out.printf("Employee. Name: %s;  Company: %s\n", super.getName(), company);
        }
    }
    

    В реализации добавляем дополнительное поле (для хранения компании) и определяем реализацию для абстрактного метода print(). Причем в реализации анонимного класса мы можем, как и в производных классах, ссылаться на функционал базового класса через ключевое слово super

Инициализаторы в анонимных классах

Как выше говорилось, мы не можем определить конструктор в анонимных классах, однако блок инициализатора для начальной инициализации:

printPerson(
    new Person("Tom"){

        private String company;

        // блок инициализатора
        {
            company = "Sber";
        }
        // реализация метода print
        @Override
        void print(){
            System.out.printf("Employee. Name: %s;  Company: %s\n", super.getName(), company);
        }
    }
);
Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850
Morty Proxy This is a proxified and sanitized view of the page, visit original site.