一、透彻分析反射的基础——Class类
1、如何得到各个字节码对应的实例对象:
1)、类名class:例如,System.class2)、对象.getClass(): 例如,new Date().getClass()
3)、Class.forName("类名"): 例如,Class.forName("java.util.Date") !常用第三种!
如下:
String str1 = "abc";
Class cls1 = String.class;
Class cls2 = str1.getClass();
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1 == cls2);//true
System.out.println(cls3 == cls2);//true 三种方式获得的都是一样
2、九个预定义Class实例对象
1)、参考Class.isPrimitive方法帮助;
2)、int.class==integer.TYPE;
3、数组类型的Class实例对象
1)、Class. isArray();
2)、总之,只要在源程序中出现的类型,都有各自的Class实例对象,例如:int[], void...
二、理解反射的概念
(一)、概念:反射就是吧Java类中的各种成分映射成相应的java类。例如:一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
学习和应用反射的要点:
通过调用Class类 的方法可以得到这些实例对象后,得到这些实例对象后有什么用?
(二)、反射的API:
1、Constructor类:
1)得到某个类所有的构造方法:
//获得方法时要用到类型
3)创建实例对象:
//调用获得的方法时要用到上面相同类型的实例对象
4)Class.newInstance()方法:
注:对字节码的比较用等号比(只有一份字节码):
2、File类——Field类代表某个类中的一个成员变量
1)问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,
如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX代表的是x的定义,而不是具体的x变量。
ReflectPoint point = new ReflectPoint(1,7);
Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");
System.out.println(y.get(point));
//Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");
Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");
x.setAccessible(true);
System.out.println(x.get(point));
ReflectPoint类的定义:
public class ReflectPoint {
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
先用getField方法获取变量x时报错,用完getDeclardField方法后还是报错,但两者的错误不一样
注:一个问题,我把自己的变量定义成private,就是不想让人家访问,可是,现在人家用暴力反射还是能够访问我,
这说不通啊,能不能让人家用暴力反射也访问不了我。首先,private主要是给javac编译器看的,希望在写程序的时候,
在源代码中不要访问我,是帮组程序员实现高内聚、低耦合的一种策略。你这个程序员不领情,非要去访问,那我拦你,由你去吧。
同样的道理,泛型集合在编译时可以帮助我们限定元素的内容,这是人家提供的好处,而你非不想要这个好处,怎么办?绕过编译器,就可以往集合中存入另外类型了。
2)作业class Xxx
{
String name="abc";
String email="abd";
int x = 5;
}
func(Object obj)
{
Field [] fields = obj.getClass().getDeclaredFields();
for(Field field : fields)
{
if(field.getType()==java.lang.String.class)
{
field.setAccesible(true);
String original = (String)field.get(obj);
field.set(obj,original.replaceAll("b","a");
}
}
}
3、Method——Method类代表某个类中的一个成员方法
1)得到类中的某一个方法:
大家应通过思考和推理的方式来学习反射中的API,例如,Class.getMethod方法用于得到一个方法,该方法要接受什么参数呢?显然要一个方法名,而一个同名的方法有多个重
载形式,用什么方式可以区分清楚想得到重载方法系列中的哪个方法呢?根据参数的个数和类型,例如,Class.getMethod(name,Class...args)中的args参数就代表所要获取的那个
方法的各个参数的类型的列表。
再强调一遍参数类型用什么来表示啊?用Class对象!
(二)、数组的反射:
1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)
2、代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class
int[] a1 = new int[4];
System.out.println(a1.getClass().getSuperclass().getName()); //打印父类的名称
控制台输出:java.lang.Object
3、基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。