8.3.1 注解简介
每个注解都必须通过一个注解接口进行定义。@interface
接口中的方法和注解中的元素相对应。@Test(timeout="10000")
元注解:Target,Retention。
8.3.2 示例:注解事件处理器,重点(工作中有价值)
组装事件源监听器是个苦差事: myButton.addActionListener(()->doSomething());
用注解免除苦差事:@ActionListenerFor(source="myButton") void doSomething(){...}
package 第8章脚本编译与注解.使用注解;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface ActionListenerFor {
String source();
}
package 第8章脚本编译与注解.使用注解;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ActionListenerInstaller {
public static void processAnnotations(Object obj) {
Class<?> cl = obj.getClass();
for (Method m : cl.getDeclaredMethods()) {
ActionListenerFor a = m.getAnnotation(ActionListenerFor.class);
if(a != null) {
try {
Field f = cl.getDeclaredField(a.source());
f.setAccessible(true);
addListener(f.get(obj), obj, m);
} catch (NoSuchFieldException | SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
public static void addListener(Object source, final Object param, final Method m) throws NoSuchMethodException, SecurityException, IllegalAccessException, InvocationTargetException {
var handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return m.invoke(param);
}
};
Object listener = Proxy.newProxyInstance(null,
new Class[] {ActionListener.class}, handler);
Method adder = source.getClass().getMethod("addActionListener", ActionListener.class);
adder.invoke(source, listener);
}
}
package 第8章脚本编译与注解.使用注解;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ButtonFrame extends JFrame{
private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 200;
private JPanel panel;
private JButton yellowButton;
private JButton blueButton;
private JButton redButton;
public ButtonFrame() {
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
panel = new JPanel();
add(panel);
yellowButton = new JButton("Yellow");
blueButton = new JButton("Blue");
redButton = new JButton("Red");
panel.add(yellowButton);
panel.add(blueButton);
panel.add(redButton);
ActionListenerInstaller.processAnnotations(this);
}
@ActionListenerFor(source = "yellowButton")
public void yellowBackground() {
panel.setBackground(Color.YELLOW);
}
@ActionListenerFor(source = "blueButton")
public void blueBackground() {
panel.setBackground(Color.BLUE);
}
@ActionListenerFor(source = "redButton")
public void redBackground() {
panel.setBackground(Color.RED);
}
public static void main(String[] args) {
var frame = new ButtonFrame();
//初始打开为屏幕中央
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screenSize = toolkit.getScreenSize();
int screenWidth = (int) screenSize.getWidth();
int screenHeight = (int) screenSize.getHeight();
//计算窗口位置
int x = (screenWidth - frame.getWidth())/2;
int y = (screenHeight - frame.getHeight())/2;
frame.setLocation(x, y);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}