Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Модуль 8. Урок 3. Анонимные классы в Java. Введение в Java

Видео может быть заблокировано из-за расширений браузера. В статье вы найдете решение этой проблемы.

Анонимные классы объявляются без указания в коде имени класса.

Анонимные классы могут быть созданы:

1) как реализация интерфейса

public class Foo {
    // Анонимный класс, который реализует интерфейс SayHello
    static SayHello h = new SayHello() {
        @Override
        public void say() {
            System.out.println("Метод внутреннего анонимного класса");
        }
    };

    public static void main(String[] args) {
        h.say();
    }
}
// somewhere 
interface SayHello {
    void say();
}

На практике, чаще, реализуют функциональные интерфейсы, с помощью анонимных классов, не смотря на наличие лямбд. Вот перечень функциональных интерфейсов из пакета java.util.function. Это не магия, а просто набор готовых заготовок для ваших будущих реализаций.

2) как наследник определённого класса

public class External {
    // Анонимный класс наследуется от класса Foo
    static Foo foo = new Foo() {
        @Override
        public void show() {
            super.show();
            System.out.println("Метод внутреннего анонимного класса");
        }
    };
    public static void main(String[] args) {
        foo.show();
    }
}

class Foo {
    public void show() {
        System.out.println("Метод суперкласса");
    }
}

Анонимный класс может быть как статическим, так и нестатическим. Это напрямую зависит от того, статическим или нестатическим является блок, в котором анонимный класс был объявлен.

Если анонимный класс объявлен в статическом блоке:

import java.util.function.Consumer;

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

        Consumer<String> foo = new Consumer() {
            @Override
            public void accept(Object o) {
                System.out.println(o + " TODO something useful!");
            }
        };

        foo.accept("Работа анонимного класса в статическом методе.");
    }
}

То его второй экземпляр можно создать так: Consumer otherInstance = foo.getClass().newInstance(); (эту строку нужно завернуть в try-catch или пробросить исключения выше). И переиспользуем ту же логику, но уже в другом инстансе: otherInstance.accept("Работа второго экземпляра анонимного класса в статическом методе.");.

Если же анонимный класс был объявлен внутри нестатического блока, то для создания второго экземпляра анонимного класса нужно передать в его конструктор ссылку на обрамляющий класс. В противном случае получим InstantiationException.

Вот как это выглядит в коде:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.function.Consumer;

public class Anonymous {

    public void nonStaticMethod() {
        // собственно наш анонимный класс
        Consumer<String> foo = new Consumer() {
            @Override
            public void accept(Object o) {
                System.out.println(o + " TODO something useful!");
            }
        };

        foo.accept("Работа анонимного класса в НЕстатическом методе.");

        // достаем конструктор у анонимного класса
        Constructor[] constructors = foo.getClass().getDeclaredConstructors();
        // Записываем ссылку на объект Anonymous в массив параметров, для конструктора.
        Object[] params = new Object[1];
        params[0] = this;

        // Создаем новую ссылку типа Consumer
        Consumer otherInstance = null;
        try {
            // создаем новый экземпляр анонимного класса, передав в его конструктор массив параметров, ссылку на текущий
            // класс, в котором мы и осуществляем все манипуляции с анонимным классом.
            otherInstance = (Consumer) constructors[0].newInstance(params);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        otherInstance.accept("Работа второго экземпляра анонимного класса в НЕстатическом методе.");
    }

    public static void main(String[] args) {
        Anonymous anon = new Anonymous();
        anon.nonStaticMethod();
    }
}

Любой анонимный внутренний класс может за один раз реализовать только один интерфейс. Так же, за один раз можно либо расширить класс, либо реализовать интерфейс, но не одновременно.

Анонимные классы полезны в некоторых "узких" участках кода, когда нет необходимости их потом переиспользовать где-то еще. Чаще всего на практике используют лишь один экземпляр анонимного класса. Если же реализацию интерфейса придется использовать много раз в коде — то лучше использовать лямбда-выражения (лямбды), которые стали доступны начиная с JAVA 8.

Например, реализацию интерфейса Consumer, в текущем уроке, можно переписать с помощью лямбд:

import java.util.function.Consumer;

public class Anonymous {

    public static void main(String[] args) {
        Consumer<String> foo = o -> System.out.println(o + " TODO something useful!");
        foo.accept(" Using lambda :)");
    }
}

Преимущества и недостатки между анонимными классами и лямбдами постепенно меняются в сторону лямбд. Об этих различиях можно почитать в статье на Хабре.

Отдельно стоит упомянуть, что не все версии Android поддерживают лямбды. И многим будет проще использовать анонимные классы, чем прикручивать лямбды.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»