用注解实现给对象动态添加方法 您所在的位置:网站首页 actionlistener接口的方法 用注解实现给对象动态添加方法

用注解实现给对象动态添加方法

2023-03-13 17:39| 来源: 网络整理| 查看: 265

来自《Java核心技术II高级特性》

我们知道在GUI编程中,有很多对象的事件监听方法,类似下面:

yellowButton.addActionListener(e -> yellowBackground());

 

首先我们先使用比较传统的方式实现这个功能

逻辑非常简单,我们定义了一个框架frame,上面有一个按钮yellowButton,点击按钮,frame会变成黄色

当然变色这个动作是通过在yellowButton上定义监听器实现的

public class ButtonFrame extends JFrame { private JPanel panel; private JButton yellowButton; public ButtonFrame() throws HeadlessException { setSize(300,200); panel=new JPanel(); add(panel); yellowButton=new JButton("Yellow"); panel.add(yellowButton); yellowButton.addActionListener(e -> yellowBackground()); } public void yellowBackground(){ panel.setBackground(Color.YELLOW); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { ButtonFrame frame = new ButtonFrame(); frame.setTitle("test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } }

 

如果我们不想每个button都addListener一遍,那有没有更优雅的办法,有!

可以通过注解+注解处理器的方式,给按钮动态添加一个监听器方法

首先我们定义一个注解ActionListennerFor

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ActionListenerFor { String source(); }

接着我们实现一个注解处理器,其中processAnnotations方法主要通过反射获取拥有自定义注解的方法,然后根据注解上的source名称获取对象的某个属性

接下来通过一个addListener方法动态的给这个属性添加一个监听器

import java.awt.event.ActionListener; import java.lang.reflect.*; public class ActionListenerInstaller { public static void processAnnotations(Object obj){ try { Class cl = obj.getClass(); //遍历对象的所有方法,查看方法上是否有我们自定义的注解ActionListenerFor for (Method m : cl.getDeclaredMethods()) { ActionListenerFor a = m.getDeclaredAnnotation(ActionListenerFor.class); if(a!=null){ String source = a.source(); //通过名称获取对象属性 Field field = cl.getDeclaredField(source); field.setAccessible(true); //给这个属性自动添加一个监听器 addListener(field.get(obj),obj,m); } } } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { e.printStackTrace(); } } public static void addListener(Object source,final Object param,final Method m) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //匿名内部类 InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method mm, Object[] args) throws Throwable { return m.invoke(param); } }; //用动态代理在运行时实现一个监听器对象 Object listener = Proxy.newProxyInstance(null, new Class[]{ActionListener.class}, handler); //通过反射获取button的addActionListener方法 Method adder = source.getClass().getMethod("addActionListener", ActionListener.class); adder.invoke(source,listener); } }

addListener是这个功能的核心部分,他是通过动态代理的方式,动态生成了一个实现了ActionListener接口的类对象

有一点要注意,handler中的invoke方法,实际调用的是被注解ActionListenerFor标记的方法

接下来又通过反射的方式,获取source所代表的button的addActionLisener这个方法,我们把它命名为adder

最后一步,adder方法invoke,参数1是所在对象source,第二个是方法的参数——listener对象

下面我把最终的代码放出来

import javax.swing.*; import java.awt.*; public class ButtonFrame extends JFrame { private JPanel panel; private JButton yellowButton; private JButton blueButton; public ButtonFrame() throws HeadlessException { setSize(300,200); panel=new JPanel(); add(panel); yellowButton=new JButton("Yellow"); panel.add(yellowButton); yellowButton.addActionListener(e -> yellowBackground()); blueButton=new JButton("Blue"); panel.add(blueButton); ActionListenerInstaller.processAnnotations(this); } public void yellowBackground(){ panel.setBackground(Color.YELLOW); } @ActionListenerFor(source="blueButton") public void blueBackground(){ panel.setBackground(Color.BLUE); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { ButtonFrame frame = new ButtonFrame(); frame.setTitle("test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } }

执行一下,发现点击黄色钮,背景变黄,点击蓝按钮,背景变蓝

我们通过了注解+注解处理器的方式,动态生成了一行代码!

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有