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

    一、什么是反射机制

    在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。简单来说,就是Java对每一个类和类中的所有成员都进行了封装,这样每个类都有一个与之对应的Class对象,通过这个对象可以直接访问类中的所有成员

    二、反射机制的作用

    ① 在运行时判断任意一个对象所属的类

    ② 在运行时构造任意一个类的对象

    ③ 在运行时判断任意一个类所具有的成员变量和方法

    ④ 在运行时调用任意一个对象的方法;生成动态代理

    三、反射机制的优点与缺点

    首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。 

    静态编译:在编译时确定类型,绑定对象,即通过。

    动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。 

    ● 优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

      比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 

    缺点对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。

    四、Java类反射中所必须的类

    除了 Class 类之外,基本都在 java.lang.reflect 包中。它们分别是:Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。

    ● Class类类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

    ● Constructor类提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。

    ● Field类提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。

    ● Method类提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。

    ● Object类每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。

    五、获取字节码方式

    在类加载的时候,jvm 会创建一个 class 对象;class 对象是反射机制中常用的,用来获取 class 对象的字节码文件

    在 Java 中可以通过三种方法获取类的字节码 (Class) 对象:

    // 获取字节码对象的三种方式
    Class c = 对象.getClass();已经创建对象一般不需要进行反射
    Class c = 类名.class;需要导入类的包,依赖性太强
    Class c = Class.forName("package.className");使用字符串获取(含包名),一般开发中选择这种★
    
    // 使用Class对象创建该对象实例:
    Object obj = c.newInstance();

    六、获取类的构造函数

    ● Constructor [] getConstructors();获取public权限的所有构造器

    ● Constructor getConstructor(Class<?>...params);根据指定参数获得public权限的构造器

    ● Constructor [] getDeclaredConstructors();获取public权限的所有构造器

    ● Constructor getDeclaredConstructor(Class<?>...params);根据指定参数获得public权限和非public权限的构造器 

    Class c = Class.forName("bean.Person");
    // 1、获取这个带有参数的构造器
    Constructor<?> con = c.getConstructor(String.class,int.class);
    // 2、使用构造器来创建:
    Object obj = con.newInsatnce("LiSi",20);

    七、获取类的字段

    ● Field [] getFields();获得类中所以public权限的方法;

    ● Field getField(String name);根据变量名得到相应的public权限的变量;

    ● Field [] getDeclaredFields();获得类中所有的public权限和非public的权限方法 ;

    ● Field getDeclaredField(String name);根据方法名获得public权限和非public权限的变量;

    package reflect;
    import java.lang.reflect.Field;
    
    public class getFieldDemo {
        public static void main(String[] args) throws Exception {
            String className = "bean.Person";
            Class<?> c = Class.forName(className);
            
            // 获取私有字段
            Field nameField = c.getDeclaredField("name");
            Field ageField = c.getDeclaredField("age");
             
            // 使用字段(使用之前我们需要一个该类对象)
            Object obj = c.newInstance();
             
            // 使用set()方法设置字段值
            nameField.setAccessible(true);
            ageField.setAccessible(true);// 暴力访问
            nameField.set(obj, "张三");
            ageField.set(obj,20);
             
            // 打印查看效果
            System.out.println("获取到的字段:");
            System.out.println("name:"+nameField);
            System.out.println("age:"+ageField);
            System.out.println("字段设置的值:name="+nameField.get(obj)+",age="+ageField.get(obj));
        }
    }

    八、获取类的方法

    ● Method [] getMethod();获取所有的public方法,包括继承的

    ● Method getMethods(String name,Class [] params);根据方法名和参数获取方法;

    ● Method [] getDeclaredMethod();获取所有public权限和非public权限方法,不包含继承的

    ● Method getDeclaredMethods(String name,Class [] params);根据方法名和参数类型,获取public权限和非public权限的方法

    package reflect;
    import java.lang.reflect.Method;
    
    public class getMethodDemo {
        public static void main(String[] args) throws Exception {
            String className = "bean.Person";
            Class<?> c = Class.forName(className);
             
            //获取公共方法:
            Method[] pubMethods = c.getMethods();
             
            //获取私有方法:
            Method[] priMethods = c.getDeclaredMethods();
             
             
            //获取单个方法:按方法名和参数获取
             
            //获取单个の静态方法:function1
            Method staMethod = c.getMethod("function1",null);
            //获取单个の无参数方法:function2
            Method nullMethod = c.getMethod("function2",null);
            //获取单个の有参数方法:function3
            Method moreMethod = c.getMethod("function3",String.class,int.class);
            //获取单个の私有方法:function4
            Method priMethod = c.getDeclaredMethod("function4",null);
            
            //打印查看效果
            System.out.println("[Person类的公共方法及父类方法:]");
            for(Method m:pubMethods){
                System.out.println(m);
            }
            System.out.println("[Person类的私有方法:]");
            for(Method m:priMethods){
                System.out.println(m);
            }
            System.out.println("[按方法名和参数类型获取的方法4个方法:]");
            System.out.println(staMethod);
            System.out.println(nullMethod);
            System.out.println(moreMethod);
            System.out.println(priMethod);    
        }
    }

    九、暴力访问setAccessible(boolean)

    对私有字段的访问取消权限检查。暴力访问(私有的不建议使用) 

  • 相关阅读:
    shell 参数个数
    小坑也难受
    MaHua简介
    airflow Operators
    datax
    T-SQL 更新表操作
    T-SQL时间函数
    linux学习网站
    好看的页面
    函数-1
  • 原文地址:https://www.cnblogs.com/Dm920/p/12462685.html
Copyright © 2011-2022 走看看