Java-反射

决定踏上高台的那一刻,便注定此生只能孤独前行。 ——冰魄林寒

Reflection 是 Java 程序开发语言的重要特征之一,是学习Java必须知识点。

Java反射机制主要提供了以下功能:在运行时构造一个类的对象;判断一个类所具有的成员变量和方法;调用一个对象的方法;生成动态代理。反射最大的应用就是框架

Java.lang.Class和Java.lang.reflect包下的API,用于表示或者处理当前JVM中的类,接口和对象。

Java反射的主要功能:

  • 确定一个对象的类

  • 取出类的modifiers,数据成员,方法,构造器,和超类.

  • 找出某个接口里定义的常量和方法说明.

  • 创建一个类实例,这个实例在运行时刻才有名字(运行时间才生成的对象).

  • 取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做到.

  • 在运行时刻调用动态对象的方法.

  • 创建数组,数组大小和类型在运行时刻才确定,也能更改数组成员的值.

Class类是Java反射的基础,Class类表示正在运行的java应用程序中的类和接口。Class只有私有的构造函数。Class类在加载类时由Java虚拟机以及调用类加载器中的 defineClass方法自动创建的。只在内存中存在一份加载类的Class类。
三种方式得到某个Java类的Class类,以java.lang.String为例:

String s = "aaa";  
Class cls1 = s.getClass();  
Class cls2 = String.class;  
Class cls3 = Class.forName("java.lang.String");  
if (cls1 == cls2) {  
    System.out.println("cls1 == cls2");  
}  
if (cls2 == cls3) {  
    System.out.println("cls2 == cls3");  
}  

为什么他们三个会==呢?因为他们描述的都是同一个类java.lang.String类。

Class类还有很多方法,配合java.lang.reflect包下的一些API可以实现更多的功能。

package org.legend.reflect;  
public class UserInfo {  
    private String userName;  
    private Integer age;  
    public String school;  

    public UserInfo() {  
    }  
    public UserInfo(String name, Integer age, String shool) {  
        this.userName = name;  
        this.age = age;  
        this.school = shool;  
    }  
    public UserInfo(String name, Integer age) {  
        this.userName = name;  
        this.age = age;  
    }  
    public String getInfo(String n, Integer i) {  
        return "success" + n + i;  
    }  
    public void getMyInfo(String mName, String mBirth, Integer age) {  
        System.out.println("我是一个来自" + mBirth + "的名叫:" + mName + "的" + age  
                           + "岁的选手");  
    }  
    public Integer getAge() {  
        return age;  
    }  
    public void setAge(Integer age) {  
        this.age = age;  
    }  
    public String getUserName() {  
        return userName;  
    }  
    public void setUserName(String userName) {  
        this.userName = userName;  
    }  
} 

一个操作类:

package org.legend.reflect;  

import java.lang.reflect.Constructor;  
import java.lang.reflect.Field;  
import java.lang.reflect.InvocationTargetException;  
import java.lang.reflect.Method;  
import java.lang.reflect.Modifier;  

/** 
 * 反射操作类 
 */  
public class GetMyInfo {  

    public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {  

        Class mclass = Class.forName("org.legend.reflect.UserInfo");  
        System.out.println("------------输出类名-----------------------");  
        System.out.println(mclass.getName());          
        System.out.println(mclass.getSimpleName()); //基础类的简称  

        //获取属性(字段)  
        System.out.println("------------输出所有属性--------------------");  
        Field[] fileds=mclass.getDeclaredFields();  //得到所有的字段,包括公共,保护,默认(包)和私有变量,但不包括继承的字段。  
        //Field[] fileds = mclass.getFields();      //得到所有的公共字段。  
        for(Field field:fileds)  
        {  
            String fieldName = field.getName();    //属性名称  
            int fieldFangWen = field.getModifiers(); //属性访问权限修饰符  
            Class fieldType = field.getType();     //属性类型  
            System.out.println(Modifier.toString(fieldFangWen)+" "+fieldType.getSimpleName()+" "+fieldName);  
        }  

        //获取方法  
        System.out.println("------------输出所有方法--------------------");  
        Method [] methods=mclass.getDeclaredMethods();  
        //Method[] medthods = mclass.getMethods();  
        for(Method method:methods)  
        {  
            String methodName = method.getName();      //方法名称  
            int methodFangWen = method.getModifiers(); //访问修饰符  
            Class methodRetrunType = method.getReturnType();//返回类型  
            Class [] methodParameter = method.getParameterTypes();//方法的参数列表  
            System.out.print(Modifier.toString(methodFangWen)+" "+methodRetrunType.getSimpleName()+" "+methodName+"(");  
            for(int k=0;k<methodParameter.length;k++)  
            {     
                String parameterName=methodParameter[k].getSimpleName();  
                if(k!=methodParameter.length-1)  
                {  
                    System.out.print(parameterName+" arg"+k+",");  
                }  
                else  
                    System.out.print(parameterName+" arg"+k);  
            }  
            System.out.println(");");  

        }  

        //获取构造  
        System.out.println("------------输出所有构造器--------------------");  
        Constructor[]constructors = mclass.getConstructors();  
        for(Constructor constructor:constructors)  
        {  
            String constructorName = constructor.getName();  
            Class[] constructorParameter = constructor.getParameterTypes();  
            System.out.print(mclass.getSimpleName()+" "+constructorName.substring(constructorName.lastIndexOf(".")+1, constructorName.length())+"(");  
            for(int h=0;h<constructorParameter.length;h++)  
            {  
                String parameterName = constructorParameter[h].getSimpleName();  
                if(h!=constructorParameter.length-1)  
                    System.out.print(parameterName+" arg"+h+",");  
                else  
                    System.out.print(parameterName+" arg"+h);  
            }  
            System.out.println(");");  

        }  

        //如何执行指定的方法  
        System.out.println("------------反射执行方法--------------------");  
        String name ="getMyInfo";  
        Class[] parameterTypes = new Class[3];  
        parameterTypes[0]= String.class;  
        parameterTypes[1]= String.class;  
        parameterTypes[2]= Integer.class;  

        Method me = mclass.getDeclaredMethod(name, parameterTypes);  
        Object obj = mclass.newInstance();  
        Object[] arg = new Object[3];  
        arg[0]="范晶晶";  
        arg[1]="AAA风景区";  
        arg[2]=new Integer(18);  
        me.invoke(obj, arg);  

    }  

} 

反射的应用很多,很多框架都有用到

spring 的 ioc/di 也是反射….
javaBean和jsp之间调用也是反射….
struts的 FormBean 和页面之间…也是通过反射调用….
JDBC 的 classForName()也是反射…..
hibernate的 find(Class clazz) 也是反射….

Class<?> clazz = Class.forName(“cn.com.huixin.blogcode.Student”)通过上述的第一种方式来获取Student的Class对象,这儿的字符串必须是类的全路径名,即包名+类名。当然,该处也可以通过上述的第二种或者第三种方法获得Student的Class对象。例如:

(1)、调用Student类的class属性

     Class<?> clazz = Student.class;

(2)、调用Student实例的getClass()方法

     Student stu = new Student();

     Class<?> clazz = stu.getClass();

无论使用哪种方法获得了Class对象,只要得到了Class对象,下来的操作方法都是相同的。

Field[] fields = clazz.getDeclaredFields()获取类中定义的属性,包括private的属性,但是不包括从父类继承下来的属性。

下来的for循环遍历了字段数组fields。field.getModifiers()获取了属性的修饰符,这个方法返回的是一个整型的数字,所以要用Modifier.toString()方法将整数转换为字符串。

Method[] methods = clazz.getDeclaredMethods()获取了类中的方法,包括private的方法,但是不包括从父类继承下来的方法。

下来遍历的方法数组methods。method.getReturnType()获得方法的返回类型。method.getParameterTypes()获得方法的参数类型,由于方法可能有多个参数,所以返回值为Class数组。

Student student = (Student)clazz.newInstance()通过调用Class对象的newInstance()方法,来创建一个Student的实例。newInstance()方法实际上调用的是默认的无参的构造方法。

Field studentName = clazz.getField("studentName")获得类中字段名为“studentName”的属性,需要注意的是,getField()方法只能获得类中的public的属性,所以将Student类中的“studentName”设置为public。

studentName.set(student, "张三")将student实例中的studentName属性值设置为“张三”。

Method finishTask = clazz.getMethod("finishTask", String.class)获得了类中的方法名为“finishTask”,并且具有一个String类型参数的方法对象。

​ finishTask.invoke(student, “数学”)调用了实例student中的finishTask方法,并且传入了一个参数。

反射框架提供的功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法(通过反射设置可以调用 private)
  • 在运行时调用人一个对象的方法

文章作者: Asxing
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Asxing !
评论
 上一篇
Mybatis源码解析(三) Mybatis源码解析(三)
Mybatis 四个插件切入点 Executor StatementHandler ParameterHandler ResultSetHandler 动态代理很熟,DefaultSQLSessionFactory,
2018-09-12
下一篇 
Mybatis源码解析(二) Mybatis源码解析(二)
没有一瞬间的脱胎换骨,生命是一次次的试探,也是一场且行且至的寻觅。 ——岚清若兮逸世凌虚 对于SqlSessionFactoryBean对于XML的解析,对于静态的文本封装为 StaticTextSql
2018-09-05
  目录