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

    参考博客:https://blog.csdn.net/sinat_38259539/article/details/71799078

    一、反射的概述

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法(指的是所有,任何的私有,静态,等等……都可以被获取到);对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。
    以上的总结就是什么是反射
    反射就是把java类中的各种成分映射成一个个的Java对象——很重要,后面的事情都是根据这个目标来进行的。
    例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把一个个组成部分映射成一个个对象
         (其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
    如图是类的正常加载过程:反射的原理在与class对象。
    熟悉一下加载的时候:Class对象的由来是jvm虚拟机通过去本地磁盘找到相应从class文件,将class文件读入内存中并为之创建一个Class对象。
    如图:

    二、下面,我们先来介绍一下Class类(基于1.7的API)

     

    Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象(包括基本数据类型)

    Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

    Class类中有64个方法,具体用到哪个再详细介绍哪个。

     

    三.获取一个类的Class对象的3种方法

      3.1 Object类下的getClas()方法

        3.2任何的数据类型(包括基本数据类型)都有一个“静态的”calss属性

        3.3通过Class类的静态方法:  Class.forName(String className)  //className是全路径名——包名+类名,但是并不是磁盘的绝对路径 (常用)

      public void f1() throws ClassNotFoundException {
            //获取class对象
            /*
            * 1.通过对象来获取字节码对象
            *   缺点:我对象都有了。。。还要字节码对象做啥子*/
            Student student=new Student();  //这样一创建 其实创建了2个对象  student对象 以及Student类对应的class对象
            Class stuClass1=student.getClass();
            /*
            * 2.通过每个类型都有的“静态的”class属性来获取
            *       缺点:依赖性太强,得导入相应的类的包;否则编译不过*/
            Class stuClass2=Student.class;
            /*
            * 常用,需要掌握  
            * Class forName(String className) 注意:全限类名*/
            Class stuClass3=Class.forName("com.kylin.FanShe.Student");
    
            System.out.println(stuClass1==stuClass2);
            System.out.println(stuClass1==stuClass3);
            System.out.println(stuClass2==stuClass3);
    
            //结果3个都是true,说明——一个类只有一个class对象
        }

    四,通过class对象获取一个类的构造方法以及通过构造方法创建对象

      通过calss对象来获取构造器,主要分获取一批构造器和获取单个构造器;    
        1.获取一批构造器      
          1.1获取所有 “共有的”构造器        
            public Constructor[] getConstructors();所有"公有的"构造方法;这个Constructor是 反射包里的 java.lang.reflect.Constructor
          1.2获取所有的(任何访问类型--包访问/共有/保护/私有)的构造器
             public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
          2.获取一个构造器(如果是无参构造器,那么参数写null或者不写
       2.1获取单个 共有的构造器
          public Constructor getConstructor(Class ... paramterTypes) ;//获取单个的“公有的”构造方法(参数是构造器参数的类型;注意是构造器参数的类型!
         2.2.获取单个任何类型的构造器
          public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有
       3.通过构造方法对象来创建对象
          Object newInstance(构造器的参数) //构造方法的一个方法,用于创建对象,返回Object类型 需要自己手动的类型转换一下

    Student.java
    package com.kylin.FanShe;
    
    public class Student {
        private String name;  //姓名
        private String sex;  //性别
        private String id;   //学号
        private int age; //年龄
    
        //4种访问类型的构造器   包访问类型  共有 保护 私有
    
        Student(){
            System.out.println("包访问类型的构造器");
        }
        //共有
        public Student(String name){
            this.name=name;
            System.out.println("共有访问类型的构造器,且名字为:"+name);
        }
    
        public Student(String id, int age){
            this.id=id;
            this.age=age;
            System.out.println("共有的构造器,id,年龄"+id+" "+age);
        }
        //保护
        protected Student(String name,String sex){
            this.name=name;
            this.sex=sex;
            System.out.println("保护类型的构造器,且名字为:"+name+"性别:"+sex);
        }
        //私有
        private Student(String name,String id,String sex){
            this.name=name;
            this.id=id;
            this.sex=sex;
            System.out.println("私有的构造器:"+name+" "+id+" "+sex);
        }
    
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }

    获取构造方法代码: (一开始引入了:import java.lang.reflect.Constructor)
      public static void main(String []args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
    //        获取class对象
            Class clazz=Class.forName("com.kylin.FanShe.Student");
            //1.1获取所有的公有的构造器
            Constructor []constructors=clazz.getConstructors();
            for (Constructor constructor:constructors){
                System.out.println(constructor);
            }
              /*
                * 结果:
                *   public com.kylin.FanShe.Student(java.lang.String,int)
                    public com.kylin.FanShe.Student(java.lang.String)
                * */
            System.out.println("-----------------------------美丽的分割线-------------------------------");
            //1.2获取所有任何类型的构造方法
            Constructor []allConstructors=clazz.getDeclaredConstructors();
            for (Constructor constructor:allConstructors){
                System.out.println(constructor);
            }
            /*
            * 结果:
            *   private com.kylin.FanShe.Student(java.lang.String,java.lang.String,java.lang.String)
                protected com.kylin.FanShe.Student(java.lang.String,java.lang.String)
                public com.kylin.FanShe.Student(java.lang.String,int)
                public com.kylin.FanShe.Student(java.lang.String)
                com.kylin.FanShe.Student()*/
    
            System.out.println("-----------------------------美丽的分割线-------------------------------");
    
            //2.1获取某个公有的 构造器
            Constructor myPubConstructor=clazz.getConstructor(String.class);  //参数是:构造器参数的类型
            System.out.println(myPubConstructor);
    //        输出:public com.kylin.FanShe.Student(java.lang.String)
    
            System.out.println("-----------------------------美丽的分割线-------------------------------");
            //2.2获取某个任何类型的构造器
            Constructor myEveConstructor=clazz.getDeclaredConstructor(String.class,String.class,String.class);
            System.out.println(myEveConstructor);
    //        输出:private com.kylin.FanShe.Student(java.lang.String,java.lang.String,java.lang.String)
    
            //通过构造方法来创建对象
            Student student= (Student) myPubConstructor.newInstance("name");
            System.out.println(student.getName());
    
    
    //          这样会抛出异常,因为一个私有的构造器不能被用来创建对象 所以需要设置访问权限
    //        Student student1= (Student) myEveConstructor.newInstance("1","22","333");
    //        System.out.println(student1.getName()+" "+student1.getId()+" "+student1.getSex());
            myEveConstructor.setAccessible(true);//暴力访问
            Student student1= (Student) myEveConstructor.newInstance("111","222","333");
            System.out.println(student1.getName()+" "+student1.getSex()+" "+student1.getId());
    
        }

      输出结果:

    public com.kylin.FanShe.Student(java.lang.String,int)
    public com.kylin.FanShe.Student(java.lang.String)
    -----------------------------美丽的分割线-------------------------------
    private com.kylin.FanShe.Student(java.lang.String,java.lang.String,java.lang.String)
    protected com.kylin.FanShe.Student(java.lang.String,java.lang.String)
    public com.kylin.FanShe.Student(java.lang.String,int)
    public com.kylin.FanShe.Student(java.lang.String)
    com.kylin.FanShe.Student()
    -----------------------------美丽的分割线-------------------------------
    public com.kylin.FanShe.Student(java.lang.String)
    -----------------------------美丽的分割线-------------------------------
    private com.kylin.FanShe.Student(java.lang.String,java.lang.String,java.lang.String)
    共有访问类型的构造器,且名字为:name
    name
    私有的构造器:111 222 333
    111 333 222

     五,通过class对象获取成员变量并调用

    teacher.java

    package com.kylin.FanShe;
    
    public class Teacher {
        public String name;
        public String name1;
        String school;
        protected String sex;
        private int age;
    
        public Teacher(){
    
        }
        @Override
        public String toString(){
            return "Teacher[name="+name+",school=" +school+
                    ",sex="+sex+",age="+age+",name1="+name1;
        }
    
    }

    测试获取成员变量并且调用

    package com.kylin.FanShe;
    
    import org.junit.Test;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    
    //获取成员变量
    public class GetFiled {
        /*
        *  获取成员变量并调用:
         *
         * 1.批量的
         *         1).Field[] getFields():获取所有的"公有字段"
         *         2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
         * 2.获取单个的:
         *         1).public Field getField(String fieldName):获取某个"公有的"字段;
         *         2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
         *
         *      设置字段的值:
         *         Field --> public void set(Object obj,Object value):
         *                     参数说明:
         *                     1.obj:要设置的字段所在的对象;
         *                     2.value:要为字段设置的值*/
    
        public static void main(String []args) throws ClassNotFoundException, NoSuchFieldException, 
        NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    //获取class对象 Class clazz=Class.forName("com.kylin.FanShe.Teacher"); //获取所有的共有的属性 Field []fields=clazz.getFields(); for (Field field:fields){ System.out.println(field); } System.out.println("-----------------------------美丽分割线-------------------------"); //获取所有的属性 (任何访问类型) Field []allFields=clazz.getDeclaredFields(); for (Field field:allFields){ System.out.println(field); //这也是一个对象来的 } System.out.println("-----------------------------美丽分割线-------------------------"); //获取指定的共有属性并且赋值给对象 Field nameField=clazz.getField("name"); System.out.println(nameField); Teacher teacher= (Teacher) clazz.getConstructor(null).newInstance(); nameField.set(teacher,"苏桃"); System.out.println(teacher); System.out.println("-----------------------------美丽分割线-------------------------"); //获取指定的任何类型(这里获取私有来测试)的属性 并且赋值给对象 Field priAgeField=clazz.getDeclaredField("age"); //女人的年龄是秘密嘛 System.out.println(priAgeField); //私有的需要设置权限 这里是暴力访问 priAgeField.setAccessible(true); priAgeField.set(teacher,20); System.out.println(teacher); } }

    输出:

    public java.lang.String com.kylin.FanShe.Teacher.name
    public java.lang.String com.kylin.FanShe.Teacher.name1
    -----------------------------美丽分割线-------------------------
    public java.lang.String com.kylin.FanShe.Teacher.name
    public java.lang.String com.kylin.FanShe.Teacher.name1
    java.lang.String com.kylin.FanShe.Teacher.school
    protected java.lang.String com.kylin.FanShe.Teacher.sex
    private int com.kylin.FanShe.Teacher.age
    -----------------------------美丽分割线-------------------------
    public java.lang.String com.kylin.FanShe.Teacher.name
    Teacher[name=苏桃,school=null,sex=null,age=0,name1=null
    -----------------------------美丽分割线-------------------------
    private int com.kylin.FanShe.Teacher.age
    Teacher[name=苏桃,school=null,sex=null,age=20,name1=null

     六,使用class对象获取成员方法并且调用(调用肯定得是该类型的对象或者子类才可以调用)

    people.java

    package com.kylin.FanShe;
    
    public class People {
    
        public void show1(String s){
            System.out.println("调用了:公有的,String参数的show1(): s = " + s);
        }
        protected void show2(){
            System.out.println("调用了:受保护的,无参的show2()");
        }
        void show3(){
            System.out.println("调用了:默认的,无参的show3()");
        }
        private String show4(int age) {
            System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
            return "abcd";
        }
    
        }

    获取成员方法并且调用

    /*
           获取成员方法并调用
                    * 1.批量的:
                   *         public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
                    *         public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
         2.获取单个的:
                   *         public Method getMethod(String name,Class<?>... parameterTypes):
                  *                     参数:
                    *                         name : 方法名;
                 *                         Class ... : 形参的Class类型对象
                public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
    
                *      调用方法:
                   *         Method --> public Object invoke(Object obj,Object... args):
                   *                     参数说明:
                   *                     obj : 要调用方法的对象,这个对象一定要是和方法同一类/或者子类也应该可以的;
                    *                     args:调用方式时所传递的实参;
                   ):
                    */
    
            public static void main(String[] args) throws Exception {
                //1.获取Class对象
                Class clazz = Class.forName("com.kylin.FanShe.People");
                //2.获取所有公有方法
                System.out.println("***************获取所有的”公有“方法*******************");
                Method[] methodArray = clazz.getMethods();
                for (Method m : methodArray) {
                    System.out.println(m);
                }
                System.out.println("***************获取所有的方法,包括私有的*******************");
                methodArray = clazz.getDeclaredMethods();
                for (Method m : methodArray) {
                    System.out.println(m);
                }
                System.out.println("***************获取公有的show1()方法*******************");
                Method pubMethod = clazz.getMethod("show1", String.class);
                System.out.println(pubMethod);
                //实例化一个Student对象
                People people= (People) clazz.getConstructor().newInstance();
                pubMethod.invoke(people,"刘德华");  //方法对象被调用执行,则输出了那句话
                System.out.println("***************获取私有的show4()方法******************");
                Method priMethod = clazz.getDeclaredMethod("show4", int.class);
                System.out.println(priMethod);
                priMethod.setAccessible(true);//解除私有限定
                System.out.println("11111111111111111111111");
    
                //抛出异常 可能是得该类的对象才可以调用
    //            Object object=new Object();
    
                People people1= (People) clazz.getConstructor().newInstance();
                priMethod.invoke(people1, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
    //            System.out.println("返回值:" + result);
    
    
            }

     总结:

      反射可以获取到一个类的所有的东西——静态的非静态的,私有的公有的……只要是在类中的,或者继承于父类的东西,都可以被获取成一个对象,然后进行调用……当然也可以获取main方法等等,这里主要介绍了通过类的字节码对象获取构造方法,成员变量,方法等……反射同时也是很多框架实现的基础,要好好琢磨……

  • 相关阅读:
    CSS 使用技巧
    CSS display
    CSS float
    .NET自动识别HttpWebResponse的编码及是否压缩
    通用权限管理系统基类中数据库的连接
    通用权限底层实现的记录软删除及表中应包含的基本字段
    最好用的兼容多种数据库通用高效的大数据分页功能
    水平权限漏洞的修复方案
    通用权限管理系统菜单展示的一个技巧
    IE11下用forms身份验证的问题
  • 原文地址:https://www.cnblogs.com/shan-kylin/p/9559347.html
Copyright © 2011-2022 走看看