Могу ли я получить доступ к новым методам в анонимном внутреннем классе с некоторым синтаксисом?
Есть ли какой-либо синтаксис Java для доступа к новым методам, определенным внутри анонимных внутренних классов из внешнего класса? Я знаю, что могут быть различные обходные пути, но мне интересно, существует ли специальный синтаксис?
Например
class Outer {
ActionListener listener = new ActionListener() {
@Override
void actionPerformed(ActionEvent e) {
// do something
}
// method is public so can be accessible
public void MyGloriousMethod() {
// viva!
}
};
public void Caller() {
listener.MyGloriousMethod(); // does not work!
}
}
МОЕ СОБСТВЕННОЕ РЕШЕНИЕ
Я просто переместил все методы и члены в внешний класс.
Ответы
Ответ 1
После того как экземпляр анонимного класса был неявным образом внесен в именованный тип, он не может быть отброшен, потому что нет имени для анонимного типа. Вы можете получить доступ к дополнительным членам анонимного внутреннего класса через this
внутри класса, в выражении сразу после выражения и типа, который может быть выведен и возвращен посредством вызова метода.
Object obj = new Object() {
void fn() {
System.err.println("fn");
}
@Override public String toString() {
fn();
return "";
}
};
obj.toString();
new Object() {
void fn() {
System.err.println("fn");
}
}.fn();
identity(new Object() {
void fn() {
System.err.println("fn");
}
}).fn();
...
private static <T> T identity(T value) {
return value;
}
Ответ 2
Студент в моем классе спросил нашего профессора, можно ли это сделать на днях. Вот что я написал как замечательное доказательство концепции, что это можно сделать, хотя это и не стоит того, что на самом деле возможно, и вот как это сделать:
public static void main(String[] args){
//anonymous inner class with method defined inside which
//does not override anything
Object o = new Object()
{
public int test = 5;
public void sayHello()
{
System.out.println("Hello World");
}
};
//o.sayHello();//Does not work
try
{
Method m = o.getClass().getMethod("sayHello");
Field f = o.getClass().getField("test");
System.out.println(f.getInt(o));
m.invoke(o);
} catch (Exception e)
{
e.printStackTrace();
}
}
Используя класс Java Method, мы можем вызывать метод, передавая строковое значение и параметры метода. То же самое можно сделать с полями.
Просто подумал, что было бы круто поделиться этим!
Ответ 3
Ваш вызывающий абонент знает listener
как ActionListener
, и поэтому он ничего не знает об этом новом методе. Я думаю, что единственный способ сделать это (кроме того, что делать рефлекторную гимнастику, которая действительно могла бы победить цель использования анонимного класса, т.е. Ярлыка/простота), - это просто подкласс ActionListener
и не использовать анонимный класс.
Ответ 4
Нет, это невозможно. Вам нужно будет указать ActionListener на его настоящее имя подкласса, но поскольку он анонимный, он не имеет имени.
Ответ 5
Правильный способ сделать это - использовать отражение:
import java.lang.reflect.InvocationTargetException;
public class MethodByReflectionTest {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
Object obj = new Object(){
public void print(){
System.out.println("Print executed.");
}
};
obj.getClass().getMethod("print", null).invoke(obj, null);
}
}
Здесь вы можете проверить: Как вызвать метод Java при указании имени метода в виде строки?
Ответ 6
Забавно, но теперь это разрешено с помощью конструкции var
(Java 10 или новее). Пример:
var calculator = new Object() {
BigDecimal intermediateSum = BigDecimal.ZERO;
void calculate(Item item) {
intermediateSum = Numbers.add(intermediateSum, item.value);
item.sum= intermediateSum;
}
};
items.forEach(calculator::calculate);
Здесь со ссылкой на метод, но, конечно, работает и с вызовом точечного метода. Работает и с полями. Наслаждайтесь новой Java. :-)
Я нашел больше трюков с var
и анонимными классами здесь: https://blog.codefx.org/java/tricks-var-anonymous-classes/
Ответ 7
Да, вы можете получить доступ к методу в приведенном ниже примере, если есть сомнения, пожалуйста, прокомментируйте
package com;
interface A
{
public void display();
}
public class Outer {
public static void main(String []args)
{
A a=new A() {
@Override
public void display() {
System.out.println("Hello");
}
};
a.display();
}
}