[关闭]
@liayun 2016-06-24T16:47:05.000000Z 字数 17488 阅读 1502

反射

java基础加强


反射的基石——Class类

Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。

一个奇怪的问题:加载了字节码,并调用了其getMethods之类的方法,但是没有看到类的静态代码块被执行,只有在第一个实例对象被创建时,这个静态代码才会被执行。准确的说,静态代码块不是在类加载时被调用的,而是第一个实例对象被创建时才执行的

反射

一个类有多个组成部分,例如:成员变量,方法,构造方法等。反射就是加载类,并解剖出类的各个组成部分
反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。

Constructor类

Constructor类代表某个类中的一个构造方法。Constructor对象代表一个构造方法,大家觉得Constructor对象上会有什么方法呢?得到名字,得到所属于的类,产生实例对象。

Field类

Field类代表某个类中的一个成员变量。
ReflectPoint类的定义如下:

  1. public class ReflectPoint {
  2. private int x;
  3. public int y;
  4. public ReflectPoint(int x, int y) { // 快捷键——Alt+Shift+S + O
  5. super();
  6. this.x = x;
  7. this.y = y;
  8. }
  9. }

以下代码会输出什么?

  1. ReflectPoint pt1 = new ReflectPoint(3, 5);
  2. Field fieldY = pt1.getClass().getField("y");
  3. // fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上的,要用它去取某个对象上对应的值
  4. System.out.println(fieldY.get(pt1)); // 5

问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?
答:类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldY代表的是y的定义,而不是具体的y变量。
以下代码:

  1. Field fieldX = pt1.getClass().getField("x");

发现会报异常:java.lang.NoSuchFieldException: x,究其原因是该字段是用private修饰的,那要获取该对象又该如何?可这样做:

  1. Field fieldX = pt1.getClass().getDeclaredField("x"); // 只要是声明的字段,不管私有还是公有

接着去取pt1对象上对应的值:

  1. System.out.println(fieldX.get(pt1));

发现还是报错,如果非要获取,怎么办,可用暴力反射

  1. fieldX.setAccessible(true); // 暴力反射
  2. System.out.println(fieldX.get(pt1)); // 3

我把自己的变量定义成private,就是不想让人家访问,可是,现在人家用暴力反射还是能够访问我,这说不通啊,能不能让人家用暴力反射也访问不了我。
首先,private主要是给javac编译器看的,希望在写程序的时候,在源代码中不要访问我,是帮组程序员实现高内聚、低耦合的一种策略。你这个程序员不领情,非要去访问,那我拦不住你,由你去吧。同样的道理,泛型集合在编译时可以帮助我们限定元素的内容,这是人家提供的好处,而你非不想要这个好处,怎么办?绕过编译器,就可以往集合中存入另外类型了。
练习一:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
解:
如有ReflectPoint类定义如下:

  1. public class ReflectPoint {
  2. private int x;
  3. public int y;
  4. public String str1 = "ball";
  5. public String str2 = "basketball";
  6. public String str3 = "itcast";
  7. public ReflectPoint(int x, int y) { // 快捷键——Alt+Shift+S + O
  8. super();
  9. this.x = x;
  10. this.y = y;
  11. }
  12. @Override
  13. public String toString() {
  14. return str1 + ":" + str2 + ":" + str3;
  15. }
  16. }

定义一个方法完成该练习:

  1. private static void changeStringValue(Object obj) throws Exception {
  2. Field[] fields = obj.getClass().getFields();
  3. for(Field field : fields) {
  4. // if(field.getType().equals(String.class))
  5. if(field.getType() == String.class) { // 因为是同一份字节码,所以用==比较(字节码用==比较)
  6. String oldValue = (String)field.get(obj);
  7. String newValue = oldValue.replace('b', 'a');
  8. field.set(obj, newValue);
  9. }
  10. }
  11. }

练习二:利用Field分别设置和获取公有、私有的属性。
先描述一个Person类,如下:

  1. public class Person {
  2. public String name = "aaaa"; // 字段反射出来是为了封装数据
  3. private int password = 123;
  4. private static int age = 23;
  5. }

反射字段

Method类

Method类代表某个类中的一个成员方法。

用反射方式执行某个类中的main方法

数组的反射

数组的反射应用

Array工具类用于完成对数组的反射操作。
例,利用反射打印一个数组:

  1. private static void printObject(Object obj) {
  2. Class clazz = obj.getClass();
  3. if(clazz.isArray()) {
  4. int len = Array.getLength(obj);
  5. for(int i = 0; i < len; i++) {
  6. System.out.println(Array.get(obj, i));
  7. }
  8. } else {
  9. System.out.println(obj);
  10. }
  11. }

调用:

  1. printObject(new String[]{"a","b","c"});
  2. printObject("xyz");

思考题:怎么得到数组中的元素类型?
答:想得到数组中的元素类型,是没有办法的,只能得到某一个具体元素的类型,不能得到整个数组的元素类型。需要取出每个元素对象,然后再对各个对象进行判断,因为其中每个具体元素的类型都可以不同,例如Object[] x = new Object[]{"abc",Integer.Max}

ArrayList、HashSet的比较及hashCode分析

关于ArrayListHashSet的比较,可参考我的Java集合框架——Collection,有结论如下:

有类ReflectPoint如下,类中覆盖hashCodeequals方法。

  1. import java.util.Date;
  2. public class ReflectPoint {
  3. private int x;
  4. public int y;
  5. public String str1 = "ball";
  6. public String str2 = "basketball";
  7. public String str3 = "itcast";
  8. public ReflectPoint(int x, int y) { // 快捷键——Alt+Shift+S + O
  9. super();
  10. this.x = x;
  11. this.y = y;
  12. }
  13. @Override
  14. public String toString() {
  15. return str1 + ":" + str2 + ":" + str3;
  16. }
  17. @Override
  18. public int hashCode() {
  19. final int prime = 31;
  20. int result = 1;
  21. result = prime * result + x;
  22. result = prime * result + y;
  23. return result;
  24. }
  25. @Override
  26. public boolean equals(Object obj) {
  27. if (this == obj)
  28. return true;
  29. if (obj == null)
  30. return false;
  31. if (getClass() != obj.getClass())
  32. return false;
  33. ReflectPoint other = (ReflectPoint) obj;
  34. if (x != other.x)
  35. return false;
  36. if (y != other.y)
  37. return false;
  38. return true;
  39. }
  40. }

分别创建ArrayList和HashSet的实例对象,比较两个集合的运行结果差异。

反射的作用——实现框架功能

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注