Как анонимные внутренние классы используются в Java? - PullRequest
293 голосов
/ 10 декабря 2008

Какая польза от анонимных классов в Java? Можно ли сказать, что использование анонимного класса является одним из преимуществ Java?

Ответы [ 18 ]

3 голосов
/ 17 ноября 2016

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

Рассмотрим пример из doc , где у нас есть Person класс:

public class Person {

    public enum Sex {
        MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    public int getAge() {
        // ...
    }

    public void printPerson() {
        // ...
    }
}

и у нас есть метод для печати членов, которые соответствуют критериям поиска:

public static void printPersons(
    List<Person> roster, CheckPerson tester) {
    for (Person p : roster) {
        if (tester.test(p)) {
            p.printPerson();
        }
    }
}

, где CheckPerson такой интерфейс, как:

interface CheckPerson {
    boolean test(Person p);
}

Теперь мы можем использовать анонимный класс, который реализует этот интерфейс, чтобы указать критерии поиска как:

printPersons(
    roster,
    new CheckPerson() {
        public boolean test(Person p) {
            return p.getGender() == Person.Sex.MALE
                && p.getAge() >= 18
                && p.getAge() <= 25;
        }
    }
);

Здесь интерфейс очень прост, а синтаксис анонимного класса кажется громоздким и неясным.

Java 8 ввел термин Функциональный интерфейс , который является интерфейсом только с одним абстрактным методом, поэтому мы можем сказать, что CheckPerson является функциональным интерфейсом. Мы можем использовать лямбда-выражение , которое позволяет нам передавать функцию в качестве аргумента метода в виде:

printPersons(
                roster,
                (Person p) -> p.getGender() == Person.Sex.MALE
                        && p.getAge() >= 18
                        && p.getAge() <= 25
        );

Мы можем использовать стандартный функциональный интерфейс Predicate вместо интерфейса CheckPerson, что еще больше сократит объем требуемого кода.

2 голосов
/ 17 декабря 2013

Анонимный внутренний класс может быть полезен, предоставляя разные реализации для разных объектов. Но следует использовать очень экономно, так как это создает проблемы для читаемости программы.

1 голос
/ 21 марта 2018

Anonymous Inner Class используется для создания объекта, на который больше никогда не будут ссылаться. Он не имеет имени и объявляется и создается в том же заявлении. Это используется там, где вы обычно используете переменную объекта. Вы заменяете переменную ключевым словом new, вызовом конструктора и определением класса внутри { и }.

При написании многопоточной программы на Java она обычно будет выглядеть так:

ThreadClass task = new ThreadClass();
Thread runner = new Thread(task);
runner.start();

ThreadClass, используемый здесь, будет определяться пользователем. Этот класс будет реализовывать интерфейс Runnable, необходимый для создания потоков. В ThreadClass метод run() (единственный метод в Runnable) также должен быть реализован. Ясно, что избавление от ThreadClass было бы более эффективным, и именно поэтому существуют анонимные внутренние классы.

Посмотрите на следующий код

Thread runner = new Thread(new Runnable() {
    public void run() {
        //Thread does it's work here
    }
});
runner.start();

Этот код заменяет ссылку на task в самом верхнем примере. Вместо того, чтобы иметь отдельный класс, анонимный внутренний класс внутри конструктора Thread() возвращает неназванный объект, который реализует интерфейс Runnable и переопределяет метод run(). Метод run() будет включать в себя операторы, выполняющие работу, требуемую потоком.

Отвечая на вопрос о том, является ли анонимные внутренние классы одним из преимуществ Java, я должен сказать, что я не совсем уверен, поскольку в настоящее время я не знаком со многими языками программирования. Но я могу сказать, что это определенно более быстрый и простой метод кодирования.

Ссылки: Сэмс научит себя Java за 21 день, седьмое издание

1 голос
/ 14 августа 2017

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

import java.util.Scanner;
abstract class AnonymousInner {
    abstract void sum();
}

class AnonymousInnerMain {
    public static void main(String []k){
        Scanner sn = new Scanner(System.in);
        System.out.println("Enter two vlaues");
            int a= Integer.parseInt(sn.nextLine());
            int b= Integer.parseInt(sn.nextLine()); 
        AnonymousInner ac = new AnonymousInner(){
            void sum(){
                int c= a+b;
                System.out.println("Sum of two number is: "+c);
            }
        };
        ac.sum();
    }

}
1 голос
/ 17 августа 2016

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

public abstract class TypeHolder<T> {
    private final Type type;

    public TypeReference() {
        // you may do do additional sanity checks here
        final Type superClass = getClass().getGenericSuperclass();
        this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }

    public final Type getType() {
        return this.type;
    }
}

Если вы создадите экземпляр этого класса анонимным способом

TypeHolder<List<String>, Map<Ineger, Long>> holder = 
    new TypeHolder<List<String>, Map<Ineger, Long>>() {};

тогда такой экземпляр holder будет содержать не стираемое определение переданного типа.

Использование

Это очень удобно для построения валидаторов / десериализаторов. Также вы можете создать экземпляр универсального типа с отражением (поэтому, если вы когда-либо хотели сделать new T() в параметризованном типе - милости просим!) .

Недостатки / Ограничения

  1. Вы должны явно передать универсальный параметр. Невыполнение этого требования приведет к потере параметра типа
  2. Каждый экземпляр будет стоить вам дополнительный класс, который будет сгенерирован компилятором, что приведет к загрязнению пути к классу / вздутию фляги
1 голос
/ 03 июля 2015

Вы можете использовать анонимный класс таким образом

TreeSet treeSetObj = new TreeSet(new Comparator()
{
    public int compare(String i1,String i2)
    {
        return i2.compareTo(i1);
    }
});
1 голос
/ 28 декабря 2012

Одно из основных применений анонимных классов при финализации классов, которое называется finalizer guardian . В мире Java следует избегать использования методов finalize до тех пор, пока они вам действительно не понадобятся. Следует помнить, что когда вы переопределяете метод finalize для подклассов, вы всегда должны также вызывать super.finalize(), потому что метод finalize суперкласса не будет вызываться автоматически, и у вас могут возникнуть проблемы с утечками памяти.

поэтому, учитывая вышеупомянутый факт, вы можете просто использовать анонимные классы, такие как:

public class HeavyClass{
    private final Object finalizerGuardian = new Object() {
        @Override
        protected void finalize() throws Throwable{
            //Finalize outer HeavyClass object
        }
    };
}

Используя эту технику, вы позволили себе и другим разработчикам вызывать super.finalize() для каждого подкласса HeavyClass, для которого требуется метод finalize.

0 голосов
/ 12 мая 2018

Еще одно преимущество:
Как вы знаете, Java не поддерживает множественное наследование, поэтому, если вы используете своего рода класс «Thread» в качестве анонимного класса, у класса все еще остается один пробел для расширения любого другого класса.

...