Как Анонимные (внутренние) классы, используемые в Java?

голоса
266

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

Задан 10/12/2008 в 06:42
источник пользователем
На других языках...                            


18 ответов

голоса
335

Под «анонимный класс», я понимаю , что вы имели в виду анонимный внутренний класс .

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

Я предпочитаю использовать его в качестве ярлыка для прикрепления слушателя событий:

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // do something
    }
});

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

Я только использовать эту технику для «быстрых и грязных» задач, где делает весь класс чувствует себя ненужным. Наличие нескольких анонимных внутренних классов, которые делают точно то же самое должны быть переработаны до фактического класса, будь то внутренний класс или отдельного класса.

Ответил 10/12/2008 в 06:50
источник пользователем

голоса
67

Анонимные внутренние классы эффективно закупорки, поэтому они могут быть использованы для эмуляции лямбда-выражения или «делегатов». Например, возьмем этот интерфейс:

public interface F<A, B> {
   B f(A a);
}

Вы можете использовать это анонимно , чтобы создать функцию первого класса в Java. Допустим, у вас есть следующий метод , который возвращает первое число больше , чем я в данном списке, или я , если число не больше:

public static int larger(final List<Integer> ns, final int i) {
  for (Integer n : ns)
     if (n > i)
        return n;
  return i;
}

И тогда у вас есть еще один метод, который возвращает первое число меньше, чем я в данном списке, или я, если число не меньше:

public static int smaller(final List<Integer> ns, final int i) {
   for (Integer n : ns)
      if (n < i)
         return n;
   return i;
}

Эти методы почти идентичны. Использование первого класса типа функции F, мы можем переписать это в один метод следующим образом:

public static <T> T firstMatch(final List<T> ts, final F<T, Boolean> f, T z) {
   for (T t : ts)
      if (f.f(t))
         return t;
   return z;
}

Вы можете использовать анонимный класс использовать метод firstMatch:

F<Integer, Boolean> greaterThanTen = new F<Integer, Boolean> {
   Boolean f(final Integer n) {
      return n > 10;
   }
};
int moreThanMyFingersCanCount = firstMatch(xs, greaterThanTen, x);

Это действительно надуманный пример, но его легко увидеть , что , будучи в состоянии передать функции вокруг , как если бы они были значения довольно полезная функция. См «Может ли ваш язык программирования это сделать» сам Джоэл.

Хорошая библиотека для программирования Java в этом стиле: Functional Java.

Ответил 10/12/2008 в 08:54
источник пользователем

голоса
39

Анонимный внутренний класс используется в следующей ситуации:

1.) Для Переопределения (Sub причислять), когда определение класса не может быть использовано, за исключением текущего случая:

class A{
   public void methodA() {
      System.out.println("methodA");
    }
}
class B{
    A a = new A() {
     public void methodA() {
        System.out.println("anonymous methodA");
     }
   };
}

2.) Для реализации интерфейса, когда РЕАЛИЗАЦИЯ интерфейса требуется только для текущего случая:

interface interfaceA{
   public void methodA();
}
class B{
   interfaceA a = new interfaceA() {
     public void methodA() {
        System.out.println("anonymous methodA implementer");
     }
   };
}

3.) Аргумент Defined анонимный внутренний класс:

 interface Foo {
   void methodFoo();
 }
 class B{
  void do(Foo f) { }
}

class A{
   void methodA() {
     B b = new B();
     b.do(new Foo() {
       public void methodFoo() {
         System.out.println("methodFoo");
       } 
     });
   } 
 } 
Ответил 09/03/2014 в 19:42
источник пользователем

голоса
39

Я использую их иногда синтаксис хак для карт конкретизации:

Map map = new HashMap() {{
   put("key", "value");
}};

против

Map map = new HashMap();
map.put("key", "value");

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

Ответил 11/12/2008 в 21:59
источник пользователем

голоса
15

Они обычно используются в качестве многословной форме обратного вызова.

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

Вот пример качели

myButton.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e) {
        // do stuff here...
    }
});

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

Ответил 10/12/2008 в 06:51
источник пользователем

голоса
7

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

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

Они, по существу, синтаксический сахар, и как правило, должны быть перемещены в другом месте, как они растут больше.

Я не уверен, если это один из преимуществ Java, хотя, если вы используете их (и все мы часто используем их, к сожалению), то можно утверждать, что они являются одним.

Ответил 10/12/2008 в 06:50
источник пользователем

голоса
6

Руководящие указания для анонимного класса.

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

  2. Анонимный класс должен расширить или реализовать к одному и только одному классу или интерфейса соответственно.

  3. Как класс Anonymouse не имеет имени, он может быть использован только один раз.

например:

button.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub

    }
});
Ответил 23/05/2012 в 18:20
источник пользователем

голоса
5
new Thread() {
        public void run() {
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                System.out.println("Exception message: " + e.getMessage());
                System.out.println("Exception cause: " + e.getCause());
            }
        }
    }.start();

Это также является одним из примера для анонимного внутреннего типа с использованием нити

Ответил 21/03/2013 в 06:59
источник пользователем

голоса
4

Да, анонимные внутренние классы, безусловно, один из преимуществ Java.

С анонимным внутренним классом, у вас есть доступ к конечным и членам переменных окружающему класса, и что пригождается в слушателях и т.д.

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

Ответил 10/12/2008 в 08:50
источник пользователем

голоса
3

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

new Thread(new Runnable() {
    public void run() {
        // you code
    }
}).start();
Ответил 10/10/2013 в 06:17
источник пользователем

голоса
2

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

Рассмотрим пример из док , где у нас есть 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, который будет способствовать дальнейшему сокращению количества кода , необходимого.

Ответил 17/11/2016 в 09:04
источник пользователем

голоса
2

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

Ответил 17/12/2013 в 07:59
источник пользователем

голоса
1

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

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экземпляр будет содержать не-erasured определение пропускаемого типа.

Применение

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

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

  1. Вы должны пройти общий параметр в явном виде. Несоблюдение этого правила приведет к потере типа параметра
  2. Каждая конкретизация будет стоить Вам дополнительный класс будет генерируемый компилятором, что приводит к пути к классам загрязнения / банку вздутие
Ответил 17/08/2016 в 20:06
источник пользователем

голоса
1

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

TreeSet treeSetObj = new TreeSet(new Comparator()
{
    public int compare(String i1,String i2)
    {
        return i2.compareTo(i1);
    }
});
Ответил 03/07/2015 в 13:23
источник пользователем

голоса
1

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

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

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

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

Ответил 28/12/2012 в 11:38
источник пользователем

голоса
0

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

Ответил 12/05/2018 в 12:22
источник пользователем

голоса
0

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

При написании программы Резьбовой в Java, то, как правило, выглядит следующим образом

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

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

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

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

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

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

Ссылки: Sams Teach Yourself Java в 21 дней седьмое издание

Ответил 21/03/2018 в 12:24
источник пользователем

голоса
0

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

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();
    }

}
Ответил 14/08/2017 в 14:18
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more