@puke3615
2016-08-18T14:52:23.000000Z
字数 3147
阅读 1144
Java是门面向对象的语言,其中的每一个对象都有与之对应的的Class。只要一提到Class,自然就想到Java的反射机制,可见反射在Java中的重要性。
1. 类名.class方式
Class cls = User.class;
2. 对象.getClass()方式
Class cls = user.getClass();
3. Class.forName()方式
//注意这里的参数是类的全限定名(即含有包名)Class cls = Class.forName("com.reflect.User");
4. ClassLoader方式
Class cls = classLoader.findClass("com.reflect.User");
1. 通过Class创建公有的无参构造方法
Class<User> cls = User.class;User user = cls.newInstance();
2.通过Constructor创建公有的无参构造方法
Class<User> cls = User.class;Constructor<User> constructor = cls.getConstructor();User user = constructor.newInstance();
3.通过Constructor创建私有的无参构造方法
Class<User> cls = User.class;Constructor<User> constructor = cls.getDeclaredConstructor();//注意,此处使用暴力反射,反射中该方法经常被使用constructor.setAccessible(true);User user = constructor.newInstance();
4.通过Constructor创建私有的含参构造方法
Class<User> cls = User.class;Constructor<User> constructor = cls.getDeclaredConstructor(String.class, int.class);constructor.setAccessible(true);//注意,此处传递的参数类型和上面的String.class和int.class保持一致User user = constructor.newInstance("小莫", 3);
public class User {public static int age;public String name;private String sex;}
1. 读写静态属性
Class<User> cls = User.class;Field ageField = cls.getField("age");//读取静态属性int age = (int) ageField.get(null);//设置静态属性ageField.set(null, 10);
2. 读写成员属性
Class<User> cls = User.class;Field nameField = cls.getField("name");//读取成员属性String name = (String) nameField.get(user);//设置成员属性nameField.set(user, "大白");
3. 读写私有成员属性
Field sexField = cls.getDeclaredField("sex");sexField.setAccessible(true);//读取私有成员属性String sex = (String) sexField.get(user);//设置私有成员属性sexField.set(user, "大白");
public class User {public static void say(String name) {System.out.println("My name is " + name);}public int plus(int a, int b) {return a + b;}}
1. 调用静态方法
Class<User> cls = User.class;//注意,这里第一个参数是指方法名,后面的参数是可变长参数,是目标方法的对应参数类型//若目标方法是无参的,则不填Method sayMethod = cls.getMethod("say", String.class);//静态方法不依赖对象实例,所以第一个参数是nullsayMethod.invoke(null, "胡巴");
后台输出:My name is 胡巴
2. 调用成员方法
User user = new User();Class<User> cls = User.class;Method plusMethod = cls.getMethod("plus", int.class, int.class);//如果该方法是非public的,则要在invoke之前调用 plusMethod.setAccessible(true);//注意,由于该方法是成员方法,它的执行依赖于一个User实例,所以第一个参数是userint result = (int) plusMethod.invoke(user, 2, 7);System.out.println(result);
后台输出:9
上面我们对于反射中一些常用的Api进行了基本的认识,接下来我们进入一个简单的实战练习,案例驱动,以加深对反射的认识。场景:我们正在使用一个第三方的jar包,包含两个类User和Dog(见下),而我们现在需求是,要调用一个User实例中dog的happy方法。public class User {private Dog dog = new Dog();}class Dog {public void sleep() {System.out.println("the dog went to bed.");}}有以下难点:1. 这两个类都是在jar包里面的,不能直接修改2. 我们要有Dog类的权限,但是Dog这个类是package的3. 我们要拿到User实例中的dog引用,但是dog属性是private的4. 我们最终要调用的sleep的方法也是private的没有反射的话,估计我们只能想到两种办法了,要么基于class字节码进行修改,要么直接找需求方互相伤害去~废话不多说,接下来我们来看通过使用反射的方式,来KO这个需求
//1. 获取user对象对应的ClassClass<User> userCls = User.class;//2. 获取到改对象的dog属性Field dogField = userCls.getDeclaredField("dog");//3. 通过dogField属性获取user实例中对应的dog实例//注意,由于Dog类是package级别的,所以这里无法直接声明Dog,只能使用Object代替dogField.setAccessible(true);Object dog = dogField.get(user);//4. 获取dog对象对象的Class对象Class<?> dogCls = dog.getClass();//这里也可以使用这种方式//Class dogCls = Class.forName("com.groovy.reflect.Dog");//5. 获取到Dog的sleep方法Method sleepMethod = dogCls.getDeclaredMethod("sleep");//6. 调用sleep方法sleepMethod.setAccessible(true);sleepMethod.invoke(dog);
后台输出:the dog went to bed.