septembre
2005
Après avoir écrit le sujet sur JDBC 4.0, je me suis demandé quel était le mécanisme permettant de générer un objet implémentant une interface à l’exécution du programme sans qu’aucune classe ne l’implémente !
Je croyais avoir mis le doigt sur une des nouveautés de Mustang… alors qu’il ne s’agit ni plus ni moins qu’une possibilité disponible depuis le JDK 1.3 via la classe proxy dynamique de l’API de réflexion : java.lang.reflect.Proxy.
Une classe proxy dynamique permet de créer des objets implémentant des interfaces, dont tous les appels de méthodes seront redirigés vers une autre classe qui s’occupera du traitement de la méthode. Il faut pour cela implémenter l’interface java.lang.reflect.InvocationHandler.
Ainsi par exemple, l’implémentation suivante se contente d’afficher un message lors de l’appel de méthode d’une interface, la méthode :
public class SysOutInvocationHandler implements InvocationHandler { public Object invoke(Object proxy, Method pMethod, Object[] pArgs) throws Throwable { Object lReturn = null; if (pMethod.getDeclaringClass().equals(Object.class)) { // Si c'est une des méthodes de la classe Object // On renvoi l'appel vers l'instance courante : lReturn = pMethod.invoke(this, pArgs); } else { // Sinon on se contente d'afficher un message : System.out.println(pMethod.getName() + "("); for (int i=0; i<pArgs.length; i++) { System.out.println(" " + pArgs[i]); } System.out.println(");"); } return lReturn; } }
Il faut ensuite utiliser la méthode Proxy.newProxyInstance() pour obtenir une instance du Proxy qui implémentera les méthodes. Par exemple, pour créer un Proxy sur l’interface KeyListener :
public static void main(String[] args) { KeyListener keyListener = (KeyListener) Proxy.newProxyInstance( ClassLoader.getSystemClassLoader(), new Class[] { KeyListener.class }, new SysOutInvocationHandler() ); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400,400); frame.setLocationRelativeTo(null); frame.addKeyListener(keyListener); frame.setVisible(true); }
Ce qui nous donne lors de la pression d’une touche :
keyPressed( java.awt.event.KeyEvent[KEY_PRESSED,keyCode=65,keyText=A,keyChar='a',keyLocation=KEY_LOCATION_STANDARD] on frame0 ); keyTyped( java.awt.event.KeyEvent[KEY_TYPED,keyCode=0,keyText=Unknown keyCode: 0x0,keyChar='a',keyLocation=KEY_LOCATION_UNKNOWN] on frame0 ); keyReleased( java.awt.event.KeyEvent[KEY_RELEASED,keyCode=65,keyText=A,keyChar='a',keyLocation=KEY_LOCATION_STANDARD] on frame0 );
Tutoriels
Discussions
- Possibilité d'accéder au type générique en runtime
- [ fuite ] memoire
- Recuperation du nom des parametres
- L'apparition du mot-clé const est-il prévu dans une version à venir du JDK?
- Difference de performances Unix/Windows d'un programme?
- [REFLEXION] Connaitre toutes les classes qui implémentent une interface
- Définition exacte de @Override
- Classes, méthodes private
- jre 1.5, tomcat 6.0 et multi processeurs