java反射---高级开发必须要懂的入门知识

来源:互联网 发布:vr视频软件 编辑:程序博客网 时间:2024/04/30 10:14

java反射说的是一套反射机制,通过这套机制我们可以访问已经装载到JVM(java虚拟机的简称)里面的某个java对象,还可以进行检测以及修改这个对象本身的信息。可以说反射机制的功能是非常强大的,在java.lang.reflect包下的类支持了这些功能。

说到反射我们绕不开的一个类Class,它到底是什么?
其实在面向对象的世界里万事万物都是对象,类也不例外;所有运行的java虚拟机中的类都是Class类的对象。
类也是对象,类是java.lang.Class类的实例对象。

知道了这个Class类的某个对象(注意这个对象是某个类,可以是java的jdk中自带的类,也可以是我们创建的类,),通过这个对象,我们就可以知道由它创建的某个实例对象的的基本信息。这个就是反射机制的直接表现形式。这样说可能有一点拗口,下面举个例子:
比如有一个类 public class A {},通过 A a=new A();我们创建了A类的一个对象 a;

 Class clz=a.getClass();//这样就获得Class类的某个对象 clz //下面通过反射机制操作这个clz,我们就可以获得实例对象a的一些基本信息:比如方法,构造方法,属性,方法参数党法修饰符等

上面只是谈了一下我对反射机制的的一般理解,不知道我说明白了?下面通过代码学习一下

1.首先如何获取Class类的对象?有如下三种方式;

package com.csdn;class Person {}//Person类public class T {    public static void main(String[] args) throws ClassNotFoundException {        Person mPerson = new Person();        // 第一种方式(任何类里面都有一个隐含的静态成员变量class)        Class p1 = Person.class;        // 第二种方式(已经知道了Person类的一个对象,比如上面mPerson)        Class p2 = mPerson.getClass();        // 第三种方式(Class.forName("类的全称"),会抛异常)        Class p3 = Class.forName("com.csdn.Person");        System.out.println(p1 == p2);// 结果为true        System.out.println(p2 == p3);// 结果为true    }}

上面也打印了p1,p2和p3的堆内存比较结果都为true,结果证明他们都是同一个;
结果同样也说明:
Class类的某个对象(类)也是唯一的
上面三种方式,不管是通过哪一种得到的Person类都是同一个,这也很好理解,因为在JVM中我们的类只可能是一个,不会存在两个一模一样的类;


2.介绍一下反射有关的几个类,当然有很多,这里只列举几个常见的;

Field类:用于操作类中的属性
Method类:用于操作类中的方法
Constructor类:提供单个构造方法的信息
Modifier类:用于解码访问修饰符(类和成员变量的访问修饰符),这个类里面全是整型常量。每个常量表示一个访问修饰符。


3.通过反射调用方法,这里要使用到Method类(方法对象),一个成员方法就是一个Method的实例对象
为上面的Person类添加一个方法

class Person {    private int height;    private int addHeight(int a) {        height = a + 1;        return height;    }    public int getHeight() {        return height;    }    public void setHeight(int height) {        this.height = height;    }}

下面通过Method类来进行操作,还是接着使用p1

        Class<?> p1 = Person.class;        /**getDeclaredMethods()获取的是本类自己声明的所有方法信息*/        Method[] mds = p1.getDeclaredMethods();        System.out.println("得到全部方法信息: ");        for (int i = 0; i < mds.length; i++)         {            /**得到方法的访问修饰权限*/            int mModify = mds[i].getModifiers();            // Modifier类里面是所有修饰符的整形常量信息            // 比如此处 public static final int PRIVATE =0x2 代表 private            // 使用Modifier.toString()方法可以将整形转化为String类型的修饰符private            System.out.print(Modifier.toString(mModify) + " ");            // 得到方法的返回值类型            Class<?> mReturnType = mds[i].getReturnType();            System.out.print(mReturnType.getName());            // 得到方法的名称            String mMethodName = mds[i].getName();            System.out.print(" " + mMethodName);            // 获取方法的参数类型            Class<?>[] mParamType = mds[i].getParameterTypes();            System.out.print("(");            // 说明当前这个方法里面没有参数类型            if (mParamType.length == 0)                System.out.println(")");            for (Class<?> mClass : mParamType) {                // 获取参数类型的名称                System.out.print(mClass.getName());                System.out.println(")");            }        }

打印的结果如下:

/**得到全部方法信息:*/ public void setHeight(int)public int getHeight()private int addHeight(int)

这里可以看到正好就是上面我们声明的Person类里面的三个方法,通过Method类我们可以很好的获取方法信息。其实我们还可以通过Method类来调用这个方法,这里方法是private修饰的不可以使用对象对象直接调用,利用反射可以轻松做到;比如我给 private int addHeight(int a) 方法传一个实参值是2,操作如下:

Class<?> p1 = Person.class;Person mPerson = new Person();//获取到某一个特定的方法对象,第一个传进去的是方法的名称,后面传入形式参数的Class类型Method md = p1.getDeclaredMethod("addHeight", int.class);//首先要获得访问的权限,打破封装md.setAccessible(true);// 调用invoke方法来调用方法第一个是Person类的对象,第二个是传递的参数int returnValue = (Integer) md.invoke(mPerson, 2);//retrunValue是addHeight(int a)方法返回的结果System.out.println("返回值: " + returnValue);System.out.println("通过mPerson得出的结果:"+mPerson.getHeight());

打印结果是

返回值: 3通过mPerson得出的结果:3

4,使用Field类来操作属性 一个Field类实例代表一个成员变量

        Class<?> p1 = Person.class;        System.out.println("得到的属性是 : ");        /** 得到本类声明的所有属性*/        Field[] mFields = p1.getDeclaredFields();        for (int i = 0; i < mFields.length; i++)         {            // 得到变量的访问修饰权限            System.out.print(Modifier.toString(mFields[i].getModifiers()) + " ");            /**得到属性的类型*/            System.out.print(mFields[i].getType().getName() + " ");            // 得到属性的名称            System.out.println(mFields[i].getName());        }

打印的结果:

得到的属性是 : private int height

当然同方法类似,通过Field也可以来直接为变量赋值的

        Class<?> p1 = Person.class;        Person mPerson = new Person();        // 获取本类声明的特定的属性,参数传入变量名称        Field mField = p1.getDeclaredField("height");        // 还是要设置一下访问权限,这步是必不可少的        mField.setAccessible(true);        // 通过setInt为对象的height属性赋值为2,因为是int型所以使用setInt        mField.setInt(mPerson, 2);        System.out.println("mPerson的height属性值是:" + mPerson.getHeight());

打印结果:

mPerson的height属性值是:2

5,使用Constructor类来操作构造方法 一个Constructor类实例代表一个构造方法对象
再为Person类添加如下构造方法

public Person() {        super();    }    private Person(int height) {        super();        this.height = height;    }

下面使用Constructor类来操作构造方法 ,接着用p1

        Class<?> p1 = Person.class;        System.out.println("得到的构造方法:");        /**获取本类声明的所有构造方法*/        Constructor<?>[] mCons = p1.getDeclaredConstructors();        for (int i = 0; i < mCons.length; i++)         {            /** 获取构造方法的访问修修饰符*/            System.out.print(Modifier.toString(mCons[i].getModifiers()) + " ");            System.out.print(mCons[i].getName());            // 得到构造方法的参数类型            Class<?>[] mConsClass = mCons[i].getParameterTypes();            System.out.print("(");            for (Class<?> css : mConsClass) {                System.out.print(css.getName());            }            System.out.println(")");        }

打印的结果:

 得到的构造方法:public com.csdn.Person()private com.csdn.Person(int)

当然了通过Constructor也可以创建Person类的对象

         Class<?> p1 = Person.class;        Constructor<?>[] mConstructs = p1.getDeclaredConstructors();        System.out.println(mConstructs.length);        for (int i = 0; i < mConstructs.length; i++) {            if (i == 0)             {// 是无参的构造方法                Person person1 = (Person) mConstructs[i].newInstance();                System.out.println("打印无参的构造方法中的Height的值:"+person1.getHeight());            } else if (i == 1)             {// 是有参的构造方法                mConstructs[i].setAccessible(true);                Person person2 = (Person) mConstructs[i].newInstance(2);                System.out.println("打印无参的构造方法中的Height的值:"+person2.getHeight());            }        }

打印结果如下:

打印无参的构造方法中的Height的值:0打印无参的构造方法中的Height的值:2

说明一下:p1.getDeclaredConstructors()得到的数组中构造方法的顺序是按照,构造方法在Person类中的声明顺序排列的,因为Person类中 先是无参,后是有参,
所以得到的数组中 第一个元素是表示无参构造方法,第二个元素是有参的构造方法
上面写法不科学,这里只是为了演示,我知道Person只有两个构造方法,才这样写的。
第二个因为不是public修饰的构造方法,所以要使用setAccessible来打破访问权限.


到这里反射机制基础知识也就介绍完了,希望对大家有所帮助,有些地方可能写的也不是很好,有错误地方请指正!

0 0
原创粉丝点击