【Java】(2)Java反射
2015-07-29 13:09
381 查看
1. 概念
J***A反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。2. 获取Class对象
public class ClassDemo1 { public static void main(String[] args) { try { Entity foo1 = new Entity(); // 获得Class对象的两种方式: Class c1 = Entity.class; Class c2 = foo1.getClass(); Class c3 = Class.forName("com.thr.reflect.Entity"); // 不管c1还是c2,都代表了Entity的class的对象 System.out.println(c1 == c2); // c3也是Entity的class对象 System.out.println(c1 == c3); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class Entity { }三种方式获取的Class对象是一致的。
通过Class对象我们还可以创建类:
Entity en = (Entity) c1.newInstance();
通过获取的这个对象就可以像用new创建出来的对象一样使用Entity内部的方法等。
3. 动态加载类
首先创建一个接口:public interface Singable { void sing(); }然后写两个实现类:
public class Bird implements Singable { @Override public void sing() { System.out.println("Bird sing..."); } }
public class Cat implements Singable { @Override public void sing() { System.out.println("Cat sing..."); } }
最后再主程序中动态加载类:
public class World { public static void main(String[] args) { try { Class c = Class.forName(args[0]); Singable singable = (Singable) c.newInstance(); singable.sing(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
运行时要传入类的全名参数。
4. 获取方法信息
首先来看基本数据类型的Class对象:public class ClassDemo2 { public static void main(String[] args) { Class[] cs = new Class[] { int.class, String.class, double.class, Double.class, void.class, Class.class }; for (Class c : cs) { System.out.println(c.getName()); System.out.println(c.getSimpleName()); } } }我们编写一个获取类的方法的工具方法:
public static void printClassMethods(Object obj) { // 首先获取Class对象 Class c = obj.getClass(); // 获取类的名称 System.out.println("类的名称是:" + c.getName()); // 获取类的方法,一个Method的对象就是一个成员方法,通过getMethods()获取的是所有public的方法,包括从父类继承而来的 // getDeclaredMethods()获取的是所有该类自己生命的方法,不问访问权限 Method[] ms = c.getMethods(); for (Method m : ms) { // 获取返回值类型 Class returnType = m.getReturnType(); System.out.print(returnType.getName() + " "); // 获取方法名 System.out.print(m.getName() + "("); // 获取参数类型 Class[] paramTypes = m.getParameterTypes(); for (Class type : paramTypes) { System.out.print(type.getName() + ","); } System.out.println(")"); } }使用它:
public static void main(String[] args) { String s = new String(); ClassUtil.printClassMethods(s); Integer i = 1; ClassUtil.printClassMethods(i); }
5. 获取成员变量和构造函数信息
获取成员变量信息:public static void printClassFields(Object obj) { // 首先获取Class对象 Class c = obj.getClass(); // 使用getFields()获取的是所有public的成员变量信息,使用getDeclaredFields获取的是该类自己声明的成员变量信息,不问访问权限 Field[] fs = c.getDeclaredFields(); for (Field f : fs) { // 获取成员变量的类型 Class fieldType = f.getType(); String typeName = fieldType.getName(); // 获取成员变量的名字 String filedName = f.getName(); System.out.println(typeName + " " + filedName); } }获取构造方法信息:
public static void printClassConstructor(Object obj) { // 首先获取Class对象 Class c = obj.getClass(); Constructor[] cons = c.getDeclaredConstructors(); for (Constructor con : cons) { // 获取方法名 System.out.print(con.getName() + "("); // 获取参数类型 Class[] paramTypes = con.getParameterTypes(); for (Class type : paramTypes) { System.out.print(type.getName() + ","); } System.out.println(")"); } }
6. 方法反射的基本操作
所有的方法对象都有一个invoke方法我们调用method.invoke(对象, 参数列表)就可以执行方法:public class MethodDemo1 { public static void main(String[] args) { try { // 获取print(int, int)方法 A a = new A(); Class c = a.getClass(); Method m1 = c.getMethod("print", int.class, int.class); // 执行方法,使用o来接受返回值 // 如果有返回值,那么Object就是返回值的类型;没有返回值就返回null Object o1 = m1.invoke(a, 10, 10); // 获取print(String, String)方法 Method m2 = c.getMethod("print", new Class[] { String.class, String.class }); Object o2 = m2.invoke(a, "s1", "s2"); // 获取print()方法 Method m3 = c.getMethod("print"); Object o3 = m3.invoke(a); System.out.println(o1); System.out.println(o2); System.out.println(o3); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } class A { public void print() { System.out.println("hello"); } public int print(int a, int b) { System.out.println(a + b); return a + b; } public String print(String a, String b) { System.out.println(a.toUpperCase() + "," + b.toLowerCase()); return a + b; } }
7. 泛型的本质
public static void main(String[] args) { List list1 = new ArrayList(); List<String> list2 = new ArrayList<String>(); Class c1 = list1.getClass(); Class c2 = list2.getClass(); System.out.println(c1 == c2); // 反射的操作都是编译之后的操作 // c1==c2是true说明编译之后集合的泛型是去泛型化的 // Java中集合的泛型是防止错误输入的,只在编译阶段有效,绕过编译就无效了 // 我们可以通过方法的反射来绕过编译 Method m; try { m = c1.getMethod("add", Object.class); m.invoke(list1, 100); System.out.println(list1.size()); System.out.println(list1); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }通过这个例子可以看到通过Java的反射机制可以绕过编译,是在运行时刻执行的,自然就可以绕过集合的泛型。
相关文章推荐
- MyEclipse编码设置
- Eclipse中c开发printf无法输出解决办法
- java开发环境搭建
- java程序bat文件启动
- Java解析json学习记录
- Android Eclipse NoClassDefFoundError
- myeclipse打开空间失败 servers不能查开
- 深入掌握JMS(八):JMSReplyTo
- 关于java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor异常
- 深入掌握JMS(七):DeliveryMode例子
- Java 正则 , 截取两个标签之间字符串
- 深入掌握JMS(六):消息头
- eclipse 启动后,闪退
- 【springmvc笔记】
- 使用 iOS 8 Spring Animation API 创建动画
- 深入掌握JMS(三):MessageListener
- 深入掌握JMS(二):一个JMS例子
- java并发编程之CountDownLatch详解
- Java splash screen
- 【SSH快速进阶】——struts2简单的实例