• 反射(1)—基本知识


    • 一、反射,被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能操作任意对象内部属性及方法。
      • 正常方式:引入需要的“包类”名称–>通过new实例化–>取得实例化对象
      • 反射方式:实例化对象–>getClass()方法–>得到完整的“包类”名称
    • 二、功能:
      • 1.在运行时判断任意一个对象所属的类
      • 2.在运行时构造任意一个类的对象
      • 3.在运行时判断一个类所具有的成员变量和方法
      • 4.在运行时调用任意一个对象的成员变量和成员方法
      • 5.生成动态代理
    • 三、Class类:对照镜子可以得到的信息,包括某个类的方法、属性、构造器、实现的那些接口,对于每个类而言JRE为每个类都保存了一个不变的Class类对象,一个Class对象包含了特定某个类的有关信息
      • 1.Class本身也是一个类
      • 2.Class对象是能由系统建立对象
      • 3.一个类在JVM中只有一个Class实例
      • 4.一个Class对象对应的是一个加载到JVM中的一个.class文件
      • 5.每个类的实例都会记得自己是由哪个Class实例所生成的
      • 6.通过Class可以得到完整的一个类的完整结构
    • 四、步骤:

      • 1.创建Class对象 Calss cla = Person.class,编辑时只是编辑成.class文件,运行时才会加载到内存
      • 2.使用newInstance()创建运行时对象,比如:Person p = cla.newInstance();
      • 3.获取运行时类的属性,比如name属性,Field f1 = cla.getField(“name”)
      • 4.并设置属性,比如name,f1.set(p, “李斯”);
    • 五、代码:

    public class TestReflection {
    
        //若不使用反射,如何创建一个对象,并调用其中的方法、属性 
        /*@Test
        public void test1(){
            Person p = new Person();
            p.setAge(22);
            p.setName("张三");
            System.out.println(p.toString());
            p.display("HK");
    
        }*/
        //使用反射创建对象
        @Test
        public void test2() throws Exception{
            Class<Person> cla = Person.class;
    
            //1.首先创建cla对应的运行时类Person类的对象
            Person p = cla.newInstance();
            System.out.println("反射机制创建对象:"+p);
    
            //2.通过反射调用并设置运行时类指定的属性
            //设置属性有两种方法,
            //其一这个属性的权限修饰符为public,使用getField()
            Field f1 = cla.getField("name");//首先获取一个属性,属性的名字叫name,赋给Field类型的变量f1
            f1.set(p, "李斯");                //其次为这个属性赋值,对象為Person,属性名为name,f1调用set方法为属性赋值
            System.out.println("为对象的一个属性name赋值:"+p);//输出这个对象
            //其二.这个属性的权限修饰符为private,使用getDeclareField()
            Field f2 = cla.getDeclaredField("age");
            //设置私有的变量允许访问。
            f2.setAccessible(true);
            f2.set(p, 22);
            System.out.println("为对象的第二个属性age赋值:"+p);
            //3.通过反射调用运行时方法,有二种其一方法有参数,方法无参数
            Method m1 = cla.getMethod("display",String.class);
            m1.invoke(p,"中国");//invoke(对象,方法形参) 
        }
        /**
         * java.long.Class类是反射的源头,getClass()返回值类型是Class类型。
         *创建一个类,通过编译(javac.exe)生成相应的.class文件,
         *之后使用java.exe加载(JVM类加载器完成).class文件,此.class文件加载到内存之后就是一个运行时类,存到缓冲区。
         *那么这个运行时类本身就是一个Class的实例。
         *1.每个运行时类只加载一次
         *2.有了Class类的实例之,才可以进行如下操作:
         *  ①创建对应的运行时类对象
         *  ②获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在包、异常、注解...)
         *  ③调用运行时类的指定结构(属性、方法、构造器)
         *  ④反射的应用:动态代理
         */
        @Test
        public void test3() throws Exception{
            Person p = new Person();
            Class clas= p.getClass();//获取该对象的类名,由哪个类创建的,以及包名路径
            System.out.println(clas == Person.class);
            System.out.println(clas);//clas = Person
            Class ca = Class.forName("反射机制.Person");
            System.out.println(ca);//ca = Person
        }
        /**
         * 如何获取Class的实例,方法有四种
         *其一:调用类本身的.class属性
         *其二:通过运行时类的对象获取,使用getClass()
         *其三:通过Class的静态方法获取
         *其四:(了解)通过类的加载器
         * @throws ClassNotFoundException 
         */
        @Test
        public void test4() throws ClassNotFoundException{
            //方法一
            Class clas1 = Person.class;
            System.out.println("方法一:"+clas1.getName());
            Class clas2 = String.class;
            System.out.println("方法一:"+clas2.getName());
            //方法二
            Person p = new Person();
            Class clas3 = p.getClass();
            System.out.println("方法二:"+clas3.getName());
            //方法三
            Class clas4 = Class.forName("反射机制.Person");
            System.out.println("方法三:"+clas4.getName());
            //方法四
            ClassLoader cl = this.getClass().getClassLoader();
            Class clas5 = cl.loadClass("反射机制.Person");
            System.out.println("方法四:"+clas5.getName());
        }
        /**
         * 类加载器:是用来将类加载进内存的,JVM规范定义了两种类加载器:启动加载器和用户自定义加载器。JVM在运行时会产生
         *三个类加载器组成初始化类加载器层次结构:依次为
         *1.引导类加载器:用C++编写是JVM自带的类加载器,负责java平台的核心库,用来加载核心类库,给加载器无法直接获取
         *2.扩展类加载器:负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库
         *3.系统类加载器:负责java-classpath或-D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器
         *
         *Bootstrap ClassLoader——>Extension ClassLoader——>System ClassLoader
         */
        @Test
        public void test5(){
            ClassLoader cl1 = ClassLoader.getSystemClassLoader();
            System.out.println(cl1);        //系统加载器
    
            ClassLoader cl2 = cl1.getParent();
            System.out.println(cl2);        //扩展加载器
    
            ClassLoader cl3 = cl2.getParent();
            System.out.println(cl3);        //引导加载器
    
            Class clas6 = Person.class;
            ClassLoader cl4 = clas6.getClassLoader();
            System.out.println(cl4);
        }
    
    
    }
  • 相关阅读:
    使用SandCastle生成代码注释文档
    如何修改默认的ModelState错误提示:字段{0}必须是一个数字
    2011总结 致:过去的30年
    CentOS下安装、配置Nginx,配合IIS做负载均衡
    灵活应用js调试技巧解决样式问题
    扩展IList对象,实现深拷贝扩展方法
    IE8对JS数组,采用属性遍历的解析差异
    如何开始Github
    Response.Clear 还是 Response.ClearHeaders
    URLRoutingModule如何处理静态文件?
  • 原文地址:https://www.cnblogs.com/tengpengfei/p/10453998.html
Copyright © 2020-2023  润新知