java反射机制

1,Java反射机制概述

  1. Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何的内部信息,并能直接操作任意对象的内 部属性及方法。

  2. 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可 以通过这个对象看到类的结构。

  3. 动态语言 vs 静态语言

    • 1、动态语言

      是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以 被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运 行时代码可以根据某些条件改变自身结构。 主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。

    • 2、静态语言

      与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、 C++。

    • Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动 态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。 Java的动态性让编程的时候更加灵活!

  4. Java反射机制提供的功能

    • 在运行时判断任意一个对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时判断任意一个类所具有的成员变量和方法
    • 在运行时获取泛型信息
    • 在运行时调用任意一个对象的成员变量和方法
    • 在运行时处理注解
    • 生成动态代理
  5. 反射相关的主要API

    获取包名 类名
    clazz.getPackage().getName()//包名
    clazz.getSimpleName()//类名
    clazz.getName()//完整类名
    
    获取成员变量定义信息
    getFields()//获取所有公开的成员变量,包括继承变量
    getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
    getField(变量名)
    getDeclaredField(变量名)
    
    获取构造方法定义信息
    getConstructor(参数类型列表)//获取公开的构造方法
    getConstructors()//获取所有的公开的构造方法
    getDeclaredConstructors()//获取所有的构造方法,包括私有
    getDeclaredConstructor(int.class,String.class)
    
    获取方法定义信息
    getMethods()//获取所有可见的方法,包括继承的方法
    getMethod(方法名,参数类型列表)
    getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
    getDeclaredMethod(方法名,int.class,String.class)
    
    反射新建实例
    clazz.newInstance();//执行无参构造创建对象
    clazz.newInstance(666,”海绵宝宝”);//执行含参构造创建对象
    clazz.getConstructor(int.class,String.class)//获取构造方法
    
    反射调用成员变量
    clazz.getDeclaredField(变量名);//获取变量
    clazz.setAccessible(true);//使私有成员允许访问
    f.set(实例,);//为指定实例的变量赋值,静态变量,第一参数给null
    f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null
    
    反射调用成员方法
    Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
    m.setAccessible(true);//使私有方法允许被调用
    m.invoke(实例,参数数据);//让指定实例来执行该方法
    
  6. 通过反射调用对象的属性,包括构造器,属性和方法

    @Test
        public void test01() throws Exception {
            //1,通过Person.class的方式获取Person类的Class对象
            Class<Person> personClass = Person.class;
            //2,通过反射创建带两个参数的构造器得到一个构造器对象
            Constructor<Person> constructor = personClass.getConstructor(String.class, String.class);
            //通过构造器对象newInstance方法创建对应的对象
            Person tom = constructor.newInstance("1", "tom");
            //查看生成的对象
            System.out.println(tom.toString());;
    
            //3,通过反射,调用对象的属性和方法
            //3.1调用属性
            Field id = personClass.getDeclaredField("id");
            id.set(tom,"2");
            System.out.println(tom);
            //3.2调用方法
            Method show = personClass.getMethod("show");
            show.invoke(tom);
        }
    
    class Person{
        public String id;
        private String name;
    
        public Person() {
    
        }
    
        private Person( String name) {
            this.name = name;
        }
    
        public Person(String id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void show(){
            System.out.println("我是张三!!");
        }
    
        private String showPerson(String name){
            System.out.println("我的名字是:"+name);
            return name;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "id='" + id + '\'' +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
  7. 通过反射调用对象的私有属性,包括构造器,属性和方法

    @Test
        public void test02() throws Exception{
            /**
             * 通过反射调用对象的私有属性,包括构造器,属性和方法
             */
            //1,通过Person.class的方式获取Person类的Class对象
            Class<Person> personClass = Person.class;
            //2,调用私有构造器方法生成对应对象
            Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(String.class);
            //3,设置declaredConstructor对象可以对Person类的私有资源进行操作
            declaredConstructor.setAccessible(true);
            //4,调用对应方法创建对象
            Person jack = declaredConstructor.newInstance("jack");
            System.out.println(jack);
            //5,调用Person类的私有属性
            Field name = personClass.getDeclaredField("name");
            name.setAccessible(true);
            name.set(jack,"jack001");
            System.out.println(jack);
            //6,调用Person类的私有方法得到对应私有方法的对象
            Method showPerson = personClass.getDeclaredMethod("showPerson",String.class);
            showPerson.setAccessible(true);
            showPerson.invoke(jack,"jack001");
            String jack001 = (String)showPerson.invoke(jack, "jack001");
            System.out.println(jack001);
        }
    

2, 理解Class类并获取Class的实例

1,Class

  1. 获取Class 类对象的三种方式
    • Class<?> clazz1 = Class.forName(“类名绝对路径”)
    • Class<?> clazz2 = 类名.class
    • Class<?> clazz3 = new 类名().getClass()
  2. 类的加载过程
    • 程序经过javac.exe命令编译为字节码文件(.class)
    • 通过java.exe对字节码文件进行解释运行,相当于将字节码文件加载到内存中,将字节码文件加载到内存中的过程就称为类的加载过程
    • 加载到内存中的类,我们称为运行时类,此运行时类就作为Class类的实例
  3. 哪些类型可以有Class对象
    • class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
    • interface:接口
    • []:数组
    • enum:枚举
    • annotation:注解@interface
    • primitive type:基本数据类型
    • void

2,类的加载与ClassLoader的理解

1,类的加载

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过 如下三个步骤来对该类进行初始化。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WapvE2Bs-1652275415469)(C:\Users\Think\AppData\Roaming\Typora\typora-user-images\1652265322892.png)]

在这里插入图片描述

类加载器的作用:

  1. **类加载的作用:**将class文件字节码内容加载到内存中,并将这些静态数据转换成方 法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为 方法区中类数据的访问入口。

  2. **类缓存:**标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器 中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。

2,ClassLoader
  1. 类加载器作用是用来把类(class)装载进内存的。JVM 规范定义了如下类型的 类的加载器。

在这里插入图片描述

  1. 几种类加载器操作

     //1.获取一个系统类加载器 
    
    ClassLoader classloader = ClassLoader.getSystemClassLoader(); 
    
    System.out.println(classloader); 
    
    //2.获取系统类加载器的父类加载器,即扩展类加载器 
    
    classloader = classloader.getParent(); 
    
    System.out.println(classloader); 
    
    //3.获取扩展类加载器的父类加载器,即引导类加载器 
    
    classloader = classloader.getParent(); 
    
    System.out.println(classloader); 
    
    //4.测试当前类由哪个类加载器进行加载 
    
    classloader = Class.forName("exer2.ClassloaderDemo").getClassLoader(); 
    
    System.out.println(classloader);
    
    //*6.关于类加载器的一个主要方法:getResourceAsStream(String str):获取类路 
    
    径下的指定文件的输入流 
    
    InputStream in = null; 
    in = this.getClass().getClassLoader().getResourceAsStream("exer2\test.properties"); 
    System.out.println(in);
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值