zoukankan      html  css  js  c++  java
  • 反射机制

    反射可以实现在运行时可以知道任意一个类的属性和方法.

    类一旦加载进内存,就会变成Class对象(字节码对象)

     

    元数据:描述输的的描述数据.

          

    反射:得到类的元数据的过程.

    在运行时期,动态的去获取某一个类中的成员信息.(构造器/属性/方法/接口/父类等等)

    并且把类中的每一种成员都描述成一个新的类

     

    Class:                表示所有的类

    Constructor:   表示所有的构造方法

    Method:          表示所有的方法

    Field:                表示所有的字段

     

    Class类是设计为泛型,所以Class类可以提供任一类的class文件

    例如:

    Java.util.Date;       使用Class类表示 class Class<Java.util.Date>;

    java.lang.Byte;       使用Class类表示 class Class<java.lang.Byte>;

     

    如何获取Class对象

    下面举例获取 java.lang.String 的字节码对象

    上述是三种获取Class对的方式,基本数据类型不能表示为对象,也就不能使用getClass的方式,基本数据类型没有类名的概念,也不能使用Class.forName的方式,所以:

    表示基本数据类型的字节码对象 所有的数据类型都有Class属性

    Class  对象名 = 数据类型.class

    九大内置Class都使用以上方式创建字节码对象:

    byte          short       int   long                 float                  double   char    boolean

    数组创建字节码对象的方式

    在Object类中说明数组也属于对象,可以调用Object类中的方法.所以创建数组的字节码对象的方式有两种:

    1):    Class 对象名 = 数组类型[].class;

    2):    Class 对象名 = 数组名.getClass();

    注意:每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

    所以:同数据类型,同维数的数组的Class对象是相等的.不区分数组内元素的个数,值.

    Class:描述所有的类/类型,所以Class类中应该具有所有类型的相同方法

    Object:描述所有的对象,所以在Object类中应该具有所有对象的共同的方法.

    通过反射来获取某一个类的构造器:

    1):获取该类的字节码对象

    常规类获取该类的字节码对象有以上的三种方式

    2):获取该类的构造器

    ①: Constructor<?> [] getConstructors();返回表示的类的所有公共构造方法,存放在Constructor数组中。

    ②: Constructor<?>[] getDeclaredConstructors();返回该类声明的所有构造方法。 存放在Constructor数组中。

    使用获取的构造器创建对象

    步骤:

    1):线找到构造器所在类的字节码对象

    2):获取构造器对象

    3):使用反射创建对象

    对于无参数外界可以直接访问的构造方法推荐使用该类中的该方法:

    public T newInstance(Object... initargs);获取该类的构造器对象

    对于有参数,则必须要获取该类有参的构造方法,然后在通过Constructor类中的newInstance加参数创建,私有的则需要设置当前的构造器可以被访问才能创建对象.

    使用反射来操作类中的方法

    步骤:

    1):线找到构造器所在类的字节码对象

    2):获取构造器对象

    3):使用反射创建对象

    4):通过对象操作类中的方法

    下列第一二种方法获取的方法列表是无序的

    Method[] getMethods();        获取该类及其父类和接口的所有公共的方法  

    Method[] getDeclaredMethods(); 获取本类的所有的方法. 

    Method getDeclaredMethod(形参数据类型.class) ;获取该类指定的方法

    获取私有的方法则需要设置当前的方法可以被访问才能创建对象.

    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import java.util.Arrays;


    class Student {
    public Student() {
    System.out.println("无参数的公共的构造器方法......");
    }

    public Student(int a) {
    System.out.println("有参数的公共的构造器方法......");
    }

    private Student(String a) {
    System.out.println("有参数的私有的构造器方法......");
    }

    protected Student(int a, int b) {
    System.out.println("受保护的构造器方法......");
    }
    public void show(){
    System.out.println("无参公共的方法");
    }
    public static void show(int...arr){
    System.out.println("int类型数组的参数被调用了,值为:" + Arrays.toString(arr));
    }
    public static void show(String...arr){
    System.out.println("String类型数组的参数被调用了,值为:" + Arrays.toString(arr));
    }
    private void show(int a){
    System.out.println("带int类型的私有的的方法");
    }
    protected void show(int a,String b){
    System.out.println("带int,String为形参受保护的方法");
    }
    }

    public class GetConstructor {

    public static void main(String[] args) throws Exception {
    //创建需要读取的类的字节码对象
    Class<Student> clz = Student.class;
    //通过该类的字节码对象获得该类的构造器
    Constructor<?>[] tor = clz.getConstructors();//此方法只获取公共的构造方法
    for (Constructor<?> constructor : tor) {
    System.out.println(constructor);
    }
    System.out.println("---------------------------------");
    tor = clz.getDeclaredConstructors();//获取该类的所有构造方法
    for (Constructor<?> constructor : tor) {
    System.out.println(constructor);
    }
    System.out.println("---------------------------------");
    //获取单个构造器getConstructor(int.class); 里面不写为读取无参数构造器 ,需要读取有参数的构造器参数里面跟上形参类型的class文件,多个用逗号隔开.
    Constructor<Student> ac = clz.getDeclaredConstructor(int.class, int.class);
    System.out.println(ac);
    System.out.println("---------------------------------");

    //使用反射机制创建非私有构造器对象
    Student student = ac.newInstance(3, 2);
    //使用反射机制创建私有的构造器对象
    //1.通过反射获取该类的私有构造器
    ac = clz.getDeclaredConstructor(String.class);
    //设置当前的构造器可以被访问
    ac.setAccessible(true);//暴力破解
    student = ac.newInstance("will");//对于私有的构造方法不能直接通过反射机制调用
    //如果一个类中的构造器没有参数,外界可以直接访问,可以使用Class类中的newInstance()方法创建对象
    student = clz.newInstance();
    //操作类中的方法
    //读取该类的公共方法包含其父类里面的公共的方法
    Method all[] = clz.getMethods();
    for (Method method : all) {
    System.out.println(method);
    }
    System.out.println("---------------------------------");
    //只返回本类的所有方法 不包含父类接口的方法
    all = clz.getDeclaredMethods();
    for (Method method : all) {
    System.out.println(method);
    }
    System.out.println("**********************************");
    //获取该类指定方法名的无参数的方法
    Method acd = clz.getDeclaredMethod("show");
    System.out.println(acd);
    //获取该类指定方法名带参的方法
    acd = clz.getDeclaredMethod("show",int.class,String.class);
    acd.invoke(student, 15,"名字");
    //操作静态方法形参为数组的方法
    Method method = clz.getMethod("show", int[].class);
    method.invoke(null, new Object[]{new int[]{1,2,3,4,5}});
    method = clz.getMethod("show", String[].class);
    method.invoke(null, new Object[]{new String[]{"A","B","C","D","E"}});


    }

    }

    使用反射调用方法:

    步骤:

    1):获取该方法的字节码对象  

    类名.class得到该类的字节码对象

    2):通过字节码对象获取该类的构造方法并创建该类的对象

    字节码对象.getDeclaredConstructor(参数.class) 获取该类的构造器

    对于私有的构造器则需要设置当前的构造器可以被访问

    构造器.setAccessible(true);

    构造器.newInstance(实参..,)得到该类的实例

    3):通过字节码对象获取该类的方法

    1.Method  对象名  =  字节码对象. getDeclaredMethod(形参数据类型.class) ;获取该类指定的方法

    对于私有的方法使用

    2.对象名.setAccessible(true);设置可访问私有成员

    4):使用反射调用方法

    对象名.invoke(该类的实例,实参);来调用该方法

    有返回值类型则接收,默认返回值类型为Object 

    针对于静态方法数组作为形参的调用

    使用反射调用静态方法

    静态方法不属于任何对象,静态方法属于类本身

    此时把invoke方法的第一个参数设置为null即可.

    使用反射调用数组参数(可变参数):

    王道: 调用方法的时候把实际参数统统作为Object数组的元素的即可.

    Methad对象.invoke(方法底层所属对象 , new Object[]{ 所有实参 });

    针对于读取泛型的方法 默认提升最高级别 Object

    把一个数组设置为Object 类型的时候,不能直接操作数组,则只能使用Array类的方法来操作数组.

    文件资源路径的加载:

    注:加载properties文件只能使用properties类的load方法

       使用方式:使用文件的相对路径,相当于classpath的跟路径(字节码输出目录)

    此时使用ClassLoader(类加载器) 类加载器默认是从classpath目录去寻找文件的

    推荐使用第二种:

  • 相关阅读:
    Java 8实战之读书笔记五:超越Java 8
    Quartz的简单使用
    Quartz实现数据库动态配置定时任务
    Java解析Groovy和Shell的代码
    Spring学习笔记(3)——快速入门
    linux的防火墙端口配置
    气泡提示 纯CSS
    解决LINUX下SQLPLUS时上下左右键乱码问题
    redhat Enterprise Linux 6 VNC安装
    使用mount命令挂载CDROM
  • 原文地址:https://www.cnblogs.com/it-xiaoBai/p/8081517.html
Copyright © 2011-2022 走看看