java基础——反射基础

来源:互联网 发布:动态ip绑定域名 编辑:程序博客网 时间:2024/05/01 21:21

一、透彻分析反射的基础——Class类

1、如何得到各个字节码对应的实例对象:

1)、类名class:例如,System.class
2)、对象.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);//trueSystem.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类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是FieldMethodContructorPackage等等。 


学习和应用反射的要点:

通过调用Class类 的方法可以得到这些实例对象后,得到这些实例对象后有什么用?


(二)、反射的API:

1、Constructor类:

1)得到某个类所有的构造方法:

Ø例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();
2)得到某一个构造方法:
Ø例子:       Constructorconstructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

  //获得方法时要用到类型

3)创建实例对象:

Ø通常方式:Stringstr = newString(new StringBuffer("abc"));
Ø反射方式: Stringstr =(String)constructor.newInstance(new StringBuffer("abc"));

  //调用获得的方法时要用到上面相同类型的实例对象

4)Class.newInstance()方法:

Ø例子:String obj =(String)Class.forName("java.lang.String").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)作业
l将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"
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)得到类中的某一个方法:


Ø例子:       MethodcharAt = Class.forName("java.lang.String").getMethod("charAt",int.class);

2)调用方法:

Ø通常方式:System.out.println(str.charAt(1));

Ø反射方式: System.out.println(charAt.invoke(str, 1));

•如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!

3)jdk1.4和jdk1.5的invoke方法的区别:

ØJdk1.5:publicObject invoke(Object obj,Object... args)

ØJdk1.4:publicObject invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的

一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, newObject[]{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[]类型使用。






原创粉丝点击