您的位置:首页 > 编程语言 > Java开发

有关Java反射的使用看这一篇就够了

2018-09-14 20:02 295 查看

1. 简介

本篇文章不探讨反射的实现机制或者说实现原理,仅仅从使用的角度去讲解我们常用的一些API接口,方便自己以后需要使用时信手拈来,同时也方便广大博友能够快速了解API的使用。

什么是反射?

反射是java语言的一个特性,它允许一个java的类获取他所有的成员变量和方法并且显示出来,这样说起来有些抽象,例如我们可以通过反射去实例化一个对象,并不非得使用new这个关键字来实例化,同时我们也可以通过反射知道Java类中有哪些变量、哪些方法等等,这些特性在C或者C++语言中是不存在的。

反射中,我们会常用到三个类,分别为Class、Method和Field,通过类名相信大家已经能够知道大概意思,分别代表类、方法和变量,本篇文章将会用大量的Demo来讲解这三个类中的部分常用重要API的作用,Demo中用到的一个实体类如下:

 
  1. public class Person {

  2.  
  3. private String name;

  4.  
  5. public Person() {

  6. System.out.println("Person()...");

  7. }

  8.  
  9. public Person(String name) {

  10. this.name = name;

  11. System.out.println("Person(String name)...");

  12. }

  13.  
  14. private void privateMethod(){

  15. System.out.println("privateMethod-->name="+this.name);

  16. }

  17.  
  18. protected void protectedMethod(){

  19. System.out.println("protectedMethod-->name="+this.name);

  20. }

  21.  
  22. void defaultMethod(){

  23. System.out.println("defaultMethod-->name="+this.name);

  24. }

  25.  
  26. public void setName(String name) {

  27. this.name = name;

  28. System.out.println("setName()...");

  29. }

  30.  
  31. public String getName() {

  32. System.out.println("getName()...");

  33. return name;

  34. }

  35.  
  36. @Override

  37. public String toString() {

  38. return "name: "+this.name;

  39. }

  40. }

2. Class 类

2.1 获取Class实例

 
  1. // 方法一 forName函数

  2. Class c= Class.forName("Person");

  3.  
  4. // 方法二 getClass()函数

  5. Person person = new Person();

  6. Class c = person.getClass();

  7.  
  8. // 方法三 使用类字面常量

  9. Class c=Person.class;

2.2 通过反射来实例化对象

 
  1. // 方法一

  2. try {

  3. Class c = Person.class;

  4. Person person = (Person) c.newInstance();

  5. System.out.println(person instanceof Person); // true

  6. } catch (InstantiationException e) {

  7. e.printStackTrace();

  8. } catch (IllegalAccessException e) {

  9. e.printStackTrace();

  10. }

  11.  
  12. // 方法二

  13. try {

  14. Class c = Class.forName("reflect.demo.Person");

  15. Person person = (Person) c.newInstance();

  16. System.out.println(person instanceof Person); // true

  17. } catch (ClassNotFoundException e) {

  18. e.printStackTrace();

  19. } catch (IllegalAccessException e) {

  20. e.printStackTrace();

  21. } catch (InstantiationException e) {

  22. e.printStackTrace();

  23. }

以上方式都是调用的Person类无参构造,如果需要调用Person(String name),改如何呢?

 
  1. // 首先获取到Person类中的有参构造,通过构造函数实例化对象

  2. try {

  3. Class c = Person.class;

  4. Constructor constructor = c.getConstructor(new Class[]{String.class});

  5. // 调用的是有参构造

  6. Person person = (Person) constructor.newInstance("jack");

  7. System.out.println(person.toString()); // name: jack

  8. } catch (NoSuchMethodException e) {

  9. e.printStackTrace();

  10. } catch (IllegalAccessException e) {

  11. e.printStackTrace();

  12. } catch (InstantiationException e) {

  13. e.printStackTrace();

  14. } catch (InvocationTargetException e) {

  15. e.printStackTrace();

  16. }

2.3 获取类中所有的方法对象

 
  1. try {

  2. Class c = Person.class;

  3. // 方式一

  4. Method [] methods = c.getMethods(); // 获取所有公共方法,且包括父类的共有方法

  5. for (Method method:methods) {

  6. System.out.print(method.getName()+", ");

  7. }

  8. System.out.println("");

  9.  
  10. // 方式二

  11. methods = c.getDeclaredMethods(); // 获取所有方法,包括私有、共有等,但是只定义在该类中

  12. for (Method method:methods) {

  13. System.out.print(method.getName()+", ");

  14. }

  15. } catch (Exception e) {

  16. e.printStackTrace();

  17. }

  18.  
  19. 输出:

  20. toString, getName, setName, wait, wait, wait, equals, hashCode, getClass, notify, notifyAll,

  21. toString, getName, setName, protectedMethod, privateMethod, defaultMethod,

  22.  
  23. // 其他

  24. Method getMethod(String name, Class<?>... parameterTypes) // 获取某个方法对象,只能是共有的

  25. Method getDeclaredMethod(String name, Class<?>... parameterTypes) // 获取获取某个方法对象,只能是当前类的,可以是private、public等

2.4 获取类中字段对象

 
  1. try {

  2. Class c = Person.class;

  3. Field[] fields = c.getFields(); // 同 getMethods

  4. for (Field field : fields) {

  5. System.out.print(field.getName() + ", ");

  6. }

  7. System.out.println("5***************");

  8. fields = c.getDeclaredFields(); // 同 getDeclaredMethods

  9. for (Field field : fields) {

  10. System.out.print(field.getName() + ", ");

  11. }

  12. } catch (Exception e) {

  13. e.printStackTrace();

  14. }

2.5 其他方法

  • getName : 返回类名,包括包名
  • getSimpleName: 返回类名,不包含包名
  • cast(Object obj):将obj类型对象转化为当前class类型对象
 
  1. Class cc = Person.class;

  2. // getName: reflect.demo.Person getSimpleName: Person

  3. System.out.println("getName: "+cc.getName()+" getSimpleName: "+cc.getSimpleName());

3. Method类

  • getName() 获取方法名
  • invoke(Object obj, Object... args) 执行obj中该方法
  • Parameter[] getParameters() 获取方法中的参数
  • setAccessible(boolean flag) 设置访问权限
 
  1. Person per = new Person();

  2. Class c = Person.class;

  3. Method method;

  4.  
  5. try {

  6. method = c.getDeclaredMethod("setName", String.class);

  7. System.out.println(method.getName()); // 输出: setName

  8. method.invoke(per, "hello reflect"); // 调用了 setName方法

  9. System.out.println(per); // 输出 name: hello reflect

  10.  
  11. Parameter[] parameters = method.getParameters();

  12. for (Parameter parameter:parameters) {

  13. System.out.print(parameter.getName()+", "); // 输出:arg0

  14. }

  15. } catch (Exception e) {

  16. e.printStackTrace();

  17. }

  18.  
  19. // 如何反射调用私有方法

  20. try {

  21. method = c.getDeclaredMethod("privateMethod");

  22. method.setAccessible(true); // 私有方法必须设置访问权限为true

  23. method.invoke(per); // 调用privateMethod方法

  24. } catch (Exception e) {

  25. e.printStackTrace();

  26. }

4. Field API

  • String getName() 获取变量名
  • setAccessible(boolean flag) 设置访问权限
  • Object get(Object obj) 获取obj对象中改变量值
  • set(Object obj, Object value) 将obj对象中的改变量值设置为value
 
  1. Class c = Person.class;

  2. Person person = new Person("lvjie");

  3. try {

  4. // Field field = c.getField("name"); // 只能获取到共有变量,包括父类

  5. Field field = c.getDeclaredField("name"); // 可以获取当前类中定义的任何变量,包括private、public等

  6. System.out.println(field.getName()); // name

  7. field.setAccessible(true); // 私有变量必须设置访问权限为true

  8. System.out.println(field.get(person)); // 获取该对象中的变量值,私有变量需要添加访问权限

  9. System.out.println(person); // name: lvjie

  10. field.set(person, "jack"); // 对该对象的变量设置值, 私有变量需要添加访问权限

  11. System.out.println(person); // name: jack

  12. } catch (Exception e) {

  13. e.printStackTrace();

  14. }

以上相关API在使用反射过程中是经常遇见的,当然还有其他相关API,例如获取该类、方法和变量上使用到的注解等等,这些在注解的使用上会做讲解。反射配合注解,会产生巨大的功能,目前许多开源库也是基于这两点技术来实现,例如Android中的 EventBus、ButterKnife、DBFlow等等。

如果对Java注解感兴趣,请看下一篇Java注解全面总结

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: