Metaprogramação – API Reflection da linguagem Java Paulo Eduardo Papotti Prof. Dr. Antonio Francisco do Prado Metraprogramação “Metaprogramação é a programação de programas que escrevem ou manipulam outros programas (ou a si próprios) assim como seus dados.” Vantagens → Maior produtividade → Menos código Desvatagens → Maior cuidado na hora de programar → Nem todas as linguagens oferecem esse recurso Metaclasse “Em orientação a objetos, uma metaclasse é uma classe cujas instâncias também são classes e não objetos no sentido tradicional. Assim como classes definem o comportamento de certos objetos, metaclasses definem o comportamento de certas classes e suas instâncias.” Em Java: Class classe = Aluno.class; Fatorial em tempo de compilação #include <iostream> using namespace std; template <int N> // Esta é a definição do template struct Fatorial { static const int valor = N * Fatorial<N - 1>::valor; }; template <> // Esta é a definição do caso base struct Fatorial<0> { static const int valor = 1; }; int main (int argc, char *argv[]) { cout << Fatorial<5>::valor << endl; cout << Fatorial<2>::valor << endl; return 0; } Java Reflection API Java manipulando Java Uma das capacidades incomuns do Java é que um programa pode analisar a si próprio. É possível descobrir: A classe de um objeto Modificadores de acesso, superclasse, campos, construtores e métodos. Se a classe implementa uma interface. É possível fazer: Criar instancia da classe Obter e modificar a variaveis de instância. Invocar um método de uma classe. Para que serve Reflection? Em programas comuns não é necessário usar Reflection. Usa-se Reflection se o seu programa necessita processar o próprio programa ou outros programas. Exemplos típicos: » Um navegador de classes » Um depurador » Um construtor de GUI » Uma IDE, tal como Netbeans ou Eclipse A classe Class Para obter informações sobre uma classe, é necessário seu objeto Class. » Se você tem um objeto obj, você pode obter seu objeto classe através: Class c = obj.getClass(); » Você pode obter a classe da superclasse de uma Class c através: Class sup = c.getSuperclass(); » Se você souber o nome da classe em tempo de compilação, você pode obter seu objeto classe através: Class c = Aluno.class; » Se você souber o nome da classe em tempo de execução em uma String str, o objeto classe pode ser obtido através: Class c = class.forName(str); Obetndo o nome da classe Se você tem uma classe de objeto c, pode-se obter o nome da classe com o comando c.getName() getName retorna o nome completo da classe (incluindo pacotes), Class c = Button.class; String s = c.getName(); System.out.println(s); irá exibir: java.awt.Button A classe Class e seus métodos estão em java.lang, que é um pacote de classes que sempre é importado para qualquer programa Java. Obtendo os modificadores de um objeto Class Os modificadores (public, final, abstract etc.) de um objeto Class podem ser acessados através do método getModifiers(). Um modifier é na verdade um int mas a classe Modifier possui métodos para definir qual é o tipo do modificador. Por exemplo: if (Modifier.isPublic(m)) System.out.println("public"); Obtendo os modificadores de um objeto Class Modifier contém esses métodos (entre outros): » » » » » » » public static boolean isAbstract(int) public static boolean isFinal(int) public static boolean isInterface(int) public static boolean isPrivate(int) public static boolean isProtected(int) public static boolean isPublic(int) public static String toString(int) Obtendo interfaces Para saber quais interfaces um objeto Class implementa basta chamar o método getInterfaces(), que retorna um array de objetos Class. Ex: static void printInterfaceNames(Object o) { Class c = o.getClass(); Class[] allInterfaces = c.getInterfaces(); for (Class inf: allInterfaces) { System.out.println(inf.getName()); } } Examinando classes e interfaces A classe Class representa tanto classes quanto interfaces Para determinar se um objeto c do tipo Class é uma interface, use-sa c.isInterface() Métodos úteis de um objeto Class são: » » » » » getModifiers() getFields() getConstructors() getMethods() isArray() Obtendo Fields public Field[] getFields() throws SecurityException » Retorna um array de Field (somente atributos públicos incluindo atributos herdados). » O tamanho do array pode ser zero » Não existe uma ordem definida para retornar os atributos, mas, em geral, eles vem na ordem que foram declarados » pulic Field getField(String name) throws NoSuchFieldException, SecurityException » Retorna o objeto Field de um determinado atributo (apenas público) » Para acessar atributos privados também, usa-se o método public Field[] getDeclaredFields() e pulic Field getDeclaredField(String name) Usando Fields Se f é um objeto Field então » » » » f.getName() retorna o nome simples do atributo f.getType() retorna o tipo (Class) do atributo f.getModifiers() retorna os Modifiers do atributo f.toString() retorna uma String contendo modificadores de acesso, o tipo, e o nome completo do atributo » Example: public java.lang.String Person.name Usando Fields Os atributos de um objeto obj podem ser acessador através: » boolean f.getBoolean(obj), int f.getInt(obj), double f.getDouble(obj), etc., retornam o valor do atributo desde que seja do tipo correto (tipos primitivos) » Object f.get(obj) retorna o atributo (objetos) » void f.set(obj, value), void f.setBoolean(obj, bool), void f.setInt(obj, i), void f.getDouble(obj, d), etc. seta o valor do atributo; Obtendo Construtores de uma classe Se c é um objeto Class, então c.getConstructors() : Constructor[] retorna um array de todos os construtores públicos de uma da classe c. c.getConstructor( Class … paramTypes ) retorna um construtor que possua os mesmos parâmetros dados por paramTypes. Ex: String.class.getConstructors().length > 15; // A classe String possui 15 construtores públicos String.class.getConstrucor( char[].class, int.class, int.class).toString() > String(char[], int,int). Construtores Se c é um objeto Constructor, então » c.getName() retorna o nome do construtor em uma String (é o mesmo nome da classe) » c.getDeclaringClass() retorna a Class no qual o construtor foi declarado » c.getModifiers() retorna os Modifier do construtor » c.getParameterTypes() retorna um array de objetos Class na ordem que foram declarados » c.newInstance(Object… initargs) cria e retorna um nova instância da classe c Exemplo Constructor c = String.class.getConstrucor( char[].class, int.class, int.class).toString() String(char[], int,int). String s = c.newInstance( new char[] {‘a’,’b’,’c’,’d’ }, 1, 2 ); s = “bc”; A classe Method public Method[] getMethods() throws SecurityException Retorna um array de objetos Method (apenas métodos públicos de uma classe ou interface, incluindo métodos herdados) Não há ordem específicas que os métodos são retornados public Method getMethod(String name, Class… parameterTypes) throws NoSuchMethodException, SecurityException Methods getDeclaringClass() → Retorna o objeto Class representando a classe ou interface que declarou o método getName() → Retorna o nome do método em uma String getModifiers() → Retorna os modificadores do método em formato int. getParameterTypes() → Retorna um array de objetos Class que representam os tipos dos parâmetros do método em questão. Methods getReturnType() → Retorna o objeto Class que representa o tipo de retorno do método toString() → Retorna uma String que descreve o método public Object invoke(Object obj, Object… args) → Invoca o método, de um determinado objeto com parâmetros especificados. Examplos de invoke() “abcdefg”.length() >> 7 Method lengthMethod = String.class.getMethod(“length”) ; lengthMethod.invoke(“abcdefg”) >> 7 “abcdefg”.substring(2, 5) >> cde Method substringMethod = String.class.getMethod ( “substring”, int.class, Integer.TYPE ) ; substringEMthod.invoke( “abcdefg”, 2, new Integer(5) ) > > cde Obtendo membros não públicos de uma classe Todos as chamadas getXXX() métodos da classe Class mencionados retorna apenas membros public da classe alvo. Para obter também membros privados, protegidos, estático existem chamadas do tipo getDeclaredXXX() getDeclaredConstructors(), getDeclaredConstrucor(Class…) getDeclaredFields(), getDeclaredField(String) getDeclaredmethods(), getDeclaredMethod(String, Class…) Mais informações Documentação http://download.oracle.com/javase/7/docs/technotes/guides/lang/index.html Exemplos de códigos http://java.sun.com/developer/codesamples/refl.html