[关闭]
@puke3615 2016-08-18T14:52:23.000000Z 字数 3147 阅读 940

Java反射—基础

Java是门面向对象的语言,其中的每一个对象都有与之对应的的Class。只要一提到Class,自然就想到Java的反射机制,可见反射在Java中的重要性。


一、 Class的几种获取方式

1. 类名.class方式

  1. Class cls = User.class;

2. 对象.getClass()方式

  1. Class cls = user.getClass();

3. Class.forName()方式

  1. //注意这里的参数是类的全限定名(即含有包名)
  2. Class cls = Class.forName("com.reflect.User");

4. ClassLoader方式

  1. Class cls = classLoader.findClass("com.reflect.User");

二、 通过反射创建对象

1. 通过Class创建公有的无参构造方法

  1. Class<User> cls = User.class;
  2. User user = cls.newInstance();

2.通过Constructor创建公有的无参构造方法

  1. Class<User> cls = User.class;
  2. Constructor<User> constructor = cls.getConstructor();
  3. User user = constructor.newInstance();

3.通过Constructor创建私有的无参构造方法

  1. Class<User> cls = User.class;
  2. Constructor<User> constructor = cls.getDeclaredConstructor();
  3. //注意,此处使用暴力反射,反射中该方法经常被使用
  4. constructor.setAccessible(true);
  5. User user = constructor.newInstance();

4.通过Constructor创建私有的含参构造方法

  1. Class<User> cls = User.class;
  2. Constructor<User> constructor = cls.getDeclaredConstructor(String.class, int.class);
  3. constructor.setAccessible(true);
  4. //注意,此处传递的参数类型和上面的String.class和int.class保持一致
  5. User user = constructor.newInstance("小莫", 3);

三、 通过反射读写对象属性
  1. public class User {
  2. public static int age;
  3. public String name;
  4. private String sex;
  5. }

1. 读写静态属性

  1. Class<User> cls = User.class;
  2. Field ageField = cls.getField("age");
  3. //读取静态属性
  4. int age = (int) ageField.get(null);
  5. //设置静态属性
  6. ageField.set(null, 10);

2. 读写成员属性

  1. Class<User> cls = User.class;
  2. Field nameField = cls.getField("name");
  3. //读取成员属性
  4. String name = (String) nameField.get(user);
  5. //设置成员属性
  6. nameField.set(user, "大白");

3. 读写私有成员属性

  1. Field sexField = cls.getDeclaredField("sex");
  2. sexField.setAccessible(true);
  3. //读取私有成员属性
  4. String sex = (String) sexField.get(user);
  5. //设置私有成员属性
  6. sexField.set(user, "大白");

四、 通过反射调用对象方法
  1. public class User {
  2. public static void say(String name) {
  3. System.out.println("My name is " + name);
  4. }
  5. public int plus(int a, int b) {
  6. return a + b;
  7. }
  8. }

1. 调用静态方法

  1. Class<User> cls = User.class;
  2. //注意,这里第一个参数是指方法名,后面的参数是可变长参数,是目标方法的对应参数类型
  3. //若目标方法是无参的,则不填
  4. Method sayMethod = cls.getMethod("say", String.class);
  5. //静态方法不依赖对象实例,所以第一个参数是null
  6. sayMethod.invoke(null, "胡巴");
  1. 后台输出:
  2. My name is 胡巴

2. 调用成员方法

  1. User user = new User();
  2. Class<User> cls = User.class;
  3. Method plusMethod = cls.getMethod("plus", int.class, int.class);
  4. //如果该方法是非public的,则要在invoke之前调用 plusMethod.setAccessible(true);
  5. //注意,由于该方法是成员方法,它的执行依赖于一个User实例,所以第一个参数是user
  6. int result = (int) plusMethod.invoke(user, 2, 7);
  7. System.out.println(result);
  1. 后台输出:
  2. 9

五、 反射的简单应用
  1. 上面我们对于反射中一些常用的Api进行了基本的认识,接下来我们进入一个简单的实战练习,案例驱动,以加深对反射的认识。
  2. 场景:我们正在使用一个第三方的jar包,包含两个类UserDog(见下),而我们现在需求是,要调用一个User实例中doghappy方法。
  3. public class User {
  4. private Dog dog = new Dog();
  5. }
  6. class Dog {
  7. public void sleep() {
  8. System.out.println("the dog went to bed.");
  9. }
  10. }
  11. 有以下难点:
  12. 1. 这两个类都是在jar包里面的,不能直接修改
  13. 2. 我们要有Dog类的权限,但是Dog这个类是package
  14. 3. 我们要拿到User实例中的dog引用,但是dog属性是private
  15. 4. 我们最终要调用的sleep的方法也是private
  16. 没有反射的话,估计我们只能想到两种办法了,要么基于class字节码进行修改,要么直接找需求方互相伤害去~
  17. 废话不多说,接下来我们来看通过使用反射的方式,来KO这个需求
  1. //1. 获取user对象对应的Class
  2. Class<User> userCls = User.class;
  3. //2. 获取到改对象的dog属性
  4. Field dogField = userCls.getDeclaredField("dog");
  5. //3. 通过dogField属性获取user实例中对应的dog实例
  6. //注意,由于Dog类是package级别的,所以这里无法直接声明Dog,只能使用Object代替
  7. dogField.setAccessible(true);
  8. Object dog = dogField.get(user);
  9. //4. 获取dog对象对象的Class对象
  10. Class<?> dogCls = dog.getClass();
  11. //这里也可以使用这种方式
  12. //Class dogCls = Class.forName("com.groovy.reflect.Dog");
  13. //5. 获取到Dog的sleep方法
  14. Method sleepMethod = dogCls.getDeclaredMethod("sleep");
  15. //6. 调用sleep方法
  16. sleepMethod.setAccessible(true);
  17. sleepMethod.invoke(dog);
  1. 后台输出:
  2. the dog went to bed.
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注