java反射简单讲解

来源:互联网 发布:游戏编程图书 编辑:程序博客网 时间:2024/05/18 03:11

java反射讲解

1 Class类的概念介绍

1.1 概念

先看一个类:Person

public class Person{}Person p1 = new Person();

众所周知,p1是Person的实例对象,那么请大家想一个问题:

Person这个类是不是一个实例对象呢?答案:是!Person类是java.lang.Class类的实例对象。

注意: 我们写的任何一个类都是Class类的实例对象。

1.2 类的实例对象表示

Person的实例对象这样表示:

Person p1 = new Person();

Person这个类也是一个实例对象(Class类的实例对象),表示方法有3种如下:

1.Class c1 = Person.class;//这句话其实也在告诉我们,任何类都有一个隐含的静态成员变量class//第二种表达方式:已知Person的对象,可以通过该类的对象获取2.Person p1 = new Person();  Class c2  = p1.getClass();//第三种表达方式3. Class c3 = Class.forName("com.czh.study.Person");

总结:

1.在官网上说c1,c2,c3都是Person类的类类型(class type)2.万事万物皆对象3.类也是对象,类是Class类的实例对象,这个对象我们称为该类的类类型。   

看到上面的3种方式大家可能会问:

既然任何一个类都是Class类的实例对象,那么为什么不用Class c4 = new Class();来表示呢?

我们来看看Class类的源码:

private Class() {    // Prevent this class to be instantiated, instance should be created by JVM only}这是Class源码中的一段,看到没Class的构造函数是私有的。这个Class的实例只能被虚拟机创建。

接下来我们来看一下上面的这3种表示方式c1,c2,c3是否相等。代码如下:

public static void main(String[] args) {    Class c1 = Person.class;    Person p1 = new Person();    Class c2 = p1.getClass();    try {        Class c3 = Class.forName("com.czh.study.Person");        System.out.println(c3 == c2);    } catch (ClassNotFoundException e) {        // TODO Auto-generated catch block        e.printStackTrace();    }    System.out.println(c1 == c2);    //我们完全可以通过类的类类型来创建该类的对象,也就是说,我们可以通过c1,c2,c3来创建Person的实例对象。        try {        Person p2 = (Person) c1.newInstance();//切记Person必须要有无参的构造方法。        p2.toString();    } catch (Exception e) {        // TODO Auto-generated catch block        e.printStackTrace();    }}输出结果:truetrue

通过上面的代码,我们可能看出:

1.三种方式创建出来的c1,c2,c3完全是相等的。2.Person p2 = (Person) c1.newInstance();中newInstance()方法的使用必须要求Person类中有无参的构造函数。

2 了解静态加载类和动态加载类的区别

Class c3 = Class.forName("类的全称");不仅表示了类的类类型,还代表了动态加载类。

举个例子:

静态加载类:

Person p1 = new Person();这句话在编译的过程中,虚拟机会加载Person类,如果Person类不存在就直接报错,编译都不会通过。这种编译时刻加载类叫静态加载类

动态加载类:

public void loadClass(String className){    Class c = Class.forName(className);    Person p = (Person)c.newInstance();}这种方式写,编译的时候不会出现任何错误。

不知道,这么写大家是否能明白。

3 通过反射获取方法信息

3.1 基本数据类型的类类型

Class c1 = int.class;//int 的类类型 Class c2 = String.class;//String类的类类型Class c3 = double.class;Class c4 = Double.class;// 注意和double.class不一样Class c5 = void.class;System.out.println(c2.getName());//包含包名的类名称System.out.println(c2.getSimpleName());//不包含包名的类名称结果:java.lang.StringString

3.2 我们来看一下Class类的基本API操作

我们来写一下打印类的信息,包括类的成员函数和变量,代码如下:

/** * @author 作者 YYD * @version 创建时间:2016年10月7日 上午6:37:23 * @function 未添加 */public class ClassUtil {    public static void printClassMessage(Object obj){        Class c = obj.getClass();//这里传递的是哪个子类的对象,c就是该子类的类类型         System.out.println("类的名称是:"+c.getName());        /**         * Method类,方法对象         * 一个成员方法,就是一个Method对象         * getMethods()方法获取是是所有的public的函数,包括父类继承的         * getDeclaredMethods()获取所有该类自己声明的方法,不问访问权限         */        Method[] methods = c.getMethods();        for (Method method : methods) {            //得到返回值类型的类类型,如果返回值是int型,那么returnType为int.class            Class returnType = method.getReturnType();            System.out.print(returnType.getName()+" ");            System.out.print(method.getName()+"(");//获取方法的名称            /**             * 获取参数类型 -->得到的是参数列表的类型的类类型。             *  如果参数是int类型,那么得到的是int.class,因为一个方法的参数可以是多个,所以得到的是一个数组             */            Class[]paramsTypes =  method.getParameterTypes();            for (Class class1 : paramsTypes) {                System.out.print(class1.getName()+",");            }            System.out.println(")");        }//      Field[]  fields = c.getFields();    }}//调用使用printClassMessage方法public static void main(String[] args) {    String str = "hello world";    ClassUtil.printClassMessage(str);}

结果如下:

int numberOfLeadingZeros(int,)int numberOfTrailingZeros(int,)int bitCount(int,)boolean equals(java.lang.Object,)java.lang.String toString(int,int,)java.lang.String toString()java.lang.String toString(int,)int hashCode(int,)int hashCode()int min(int,int,)int max(int,int,)int reverseBytes(int,)int compareTo(java.lang.Integer,)...太多就不一一显示了,大家可以试一下

4 通过反射获取成员变量和构造函数信息

注意:成员变量也是对象,在java.lang.reflect.Field中Field类封装了关于成员变量的操作

4.1 获取成员变量的信息

代码如下:

/** * getFields() 获取所有public的成员变量的信息 * getDeclaredFields()获取自己声明的成员变量信息,无论访问权限 * @param obj */public static void printClassFieldMsg(Object obj){    Class c = obj.getClass();    Field[]  fields = c.getDeclaredFields();    for (Field field : fields) {        //field.getType()获取成员变量类型的类类型,如果类型是int型,那么得到的是int.class        System.out.println(field.getType().getName()+" "+field.getName());    }}Integer inte = new Integer(1);ClassUtil.printClassFieldMsg(inte);结果如下:    int MIN_VALUE    int MAX_VALUE    java.lang.Class TYPE    [C digits    [C DigitTens    [C DigitOnes    [I sizeTable    int value    int SIZE    int BYTES    long serialVersionUID

4.2 获取构造方法的信息

代码如下:

/** * 打印构造函数的信息 * @param obj */public static void printConstructmsg(Object obj){    Class c = obj.getClass();    /**     * 构造函数也是对象,java.long.Constructor封装了构造函数的信息     */    Constructor[]  cons = c.getDeclaredConstructors();    for (Constructor constructor : cons) {        System.out.print(constructor.getName()+"(");        Parameter[] p = constructor.getParameters();        for (Parameter parameter : p) {            System.out.print(parameter.getType().getSimpleName()+" "+parameter.getName()+",");        }        System.out.println(")");    }}//调用方法ClassUtil.printConstructmsg("hello");结果如下:    java.lang.String(byte[] arg0,int arg1,int arg2,)    java.lang.String(byte[] arg0,Charset arg1,)    java.lang.String(byte[] arg0,String arg1,)    java.lang.String(byte[] arg0,int arg1,int arg2,Charset arg3,)    java.lang.String(byte[] arg0,int arg1,int arg2,String arg3,)    java.lang.String(char[] arg0,boolean arg1,)    java.lang.String(StringBuilder arg0,)    java.lang.String(StringBuffer arg0,)    java.lang.String(byte[] arg0,)    java.lang.String(int[] arg0,int arg1,int arg2,)    java.lang.String()    java.lang.String(char[] arg0,)    java.lang.String(String arg0,)    java.lang.String(char[] arg0,int arg1,int arg2,)    java.lang.String(byte[] arg0,int arg1,)    java.lang.String(byte[] arg0,int arg1,int arg2,int arg3,)

5 方法反射的基本操作

方法反射的操作如下:

method.invoke(对象,参数列表)

举例代码如下:

/** * @author 作者 YYD * @version 创建时间:2016年10月7日 上午6:38:08 * @function 未添加 */public class Client {    public static void main(String[] args) {        /**        *首先获取类的类类型        *第二获取方法getMethod()和*getDelcaredMethod()        */            try {                Person person = new Person();                Class p = person.getClass();                Method m = p.getMethod("add",int.class,int.class);              //m.setAccessible(true);//注意,如果add方法是private的,如果要调用,就需要加上这样一句话                  //方法的反射操作是用m对象来进行方法调用                                   m.invoke(person, 1,1);            } catch (Exception e) {                // TODO Auto-generated catch block                e.printStackTrace();            }    }} class Person {    public void add(int a,int b){        System.out.println(a + b);    }}

6 属性反射的基本操作

现在我们来讲一下,如何通过反射访问私有变量,并且赋值。代码如下:

//访问私有变量  public static void main(String[] args) {        try {            Class c = Class.forName("com.czh.study.Person");            Field f = c.getDeclaredField("age");            f.setAccessible(true);// 调用private属性的关键一句话            Person person = (Person) c.newInstance();            f.set(person, 10);//给属性赋值和获取属性的值必须是相同的对象            System.out.println(f.get(person));//给属性赋值和获取属性的值必须是相同的对象        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }}

7 总结

好了,就讲到这里吧,希望对大家有所帮助。

0 0
原创粉丝点击