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

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

Ответы [ 18 ]

354 голосов
/ 10 декабря 2008

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

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

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

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

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

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

73 голосов
/ 10 декабря 2008

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

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

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

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

И затем у вас есть другой метод, который возвращает первое число, меньшее, чем i в данном списке, или 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 в этом стиле: Функциональная Java.

51 голосов
/ 09 марта 2014

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

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

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.) Определенный аргумент Анонимный внутренний класс:

 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");
       } 
     });
   } 
 } 
45 голосов
/ 11 декабря 2008

Я использую их иногда как синтаксический взлом для создания экземпляров Map:

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

против

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

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

18 голосов
/ 10 декабря 2008

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

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

Вот пример свинга

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

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

8 голосов
/ 10 декабря 2008

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

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

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

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

6 голосов
/ 23 мая 2012

GuideLines для анонимного класса.

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

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

  3. Поскольку у класса anonymouse нет имени, его можно использовать только один раз.

Например:

button.addActionListener(new ActionListener(){

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

    }
});
5 голосов
/ 21 марта 2013
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();

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

5 голосов
/ 10 декабря 2008

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

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

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

4 голосов
/ 10 октября 2013

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

new Thread(new Runnable() {
    public void run() {
        // you code
    }
}).start();
...