尚硅谷_初级_反射(636-661)动态代理(662-663)

https://www.bilibili.com/video/BV1Kb411W75N?p=636
一:java 反射 机制概述
    1.反射(Reflecttion):
        反射 被视为 动态语言 的关键,反射机制 允许程序 在执行期,借助于 Reflection API,
        取得任何 类的 内部信息,并能直接操作 任意对象的 内部属性及方法。
    2.反射:
        加载完类之后,在堆内存的方法区中,就产生一个 class 类型的对象,这个 class 对象,
        包含了 类的完整信息,可以通过这个 class 对象,看到类的结构。
    3.反射相关主要 API:
        Method:方法
        Field:代表类的成员变量
        Constructor:代表类的构造器
    面试:
        1)通过new方式 或者 反射方式都可以调用公共类结构,开发中到底用哪个?
            建议:用 new
            动态的创建,会用到反射
        2)反射机制 与 面向对象中的封装性,是不是矛盾的?如何看待两个技术?
            不矛盾,封装性:不建议,也不能够,调用私有的属性和方法。
                    反射:虽然不建议,但是可以调用的。


二:理解 Class 类,并 获取 Class 实例
    1.理解 Class 类
        1)类加载过程:
            程序经过 javac 命令后,会生成一个字节码文件(.class),结尾,
                接着使用 java 对字节码文件,进行解释运行。
                就相当于 把字节码对象加载到内存中。此过程,称为类的加载。
                加载到内存中的类,我们就称为运行时类,此运行时类,就称为 一个 Class 实例。
    2.Class 实例的获取:
        注意:
            Class<? extends Person> b
            Class 类,加上泛型限制,避免了 之后在使用(newInstance),再去强转。
        1)方式一:
            Class<Person> a = Person.class;
        2)方式二:
            Person p1 = new Person();
            Class<? extends Person> b = p1.getClass();
        3)方式三:
            Class<?> c = forName("com.classloader.Son");
        4)方式四:(了解,使用类加载器)
            //获取 ClassLoader 类加载器
            ClassLoader classLoader = Test1.class.getClassLoader();
            Class<?> d = classLoader.loadClass("com.classloader.Son");
        注意:a,b,c,d 指向同一个对象。
    3.哪些类型 可以有 Class 对象
        1)class:类(外部类,内部类)
        2)interface:接口
        3)[]:数组
        4)enum:枚举
        5)annotation:注解@interface
        6)基本数据类型
        7)void
    4.只要 数组的 元素类型 与 维度 一样,就是同一个 class
        元素类型:int,String,Byte。
        维度:一维数组,二维数组。
        


三:类的加载 与 ClassLoader 的理解
    1.类的加载过程:
        1)类的加载(Load):
            java 命令,将 class 文件,加载到内存,并将这些静态数据,
            转换成方法区的,运行时数据结构。并为之创建一个 Class 实例。
            此过程由类加载器完成。
        2)类的链接(Link):
            将 Java 类的二进制代码,合并到 JVM 的运行状态之中的过程。
                验证:确保加载类信息符合 JVM 规范
                准备:为 类变量(static),分配内存,并设置类变量默认初始值,在方法去中分配。
                解析:虚拟机常量池内 的符号引用(常量名),替换为直接引用(地址)的过程。
        3)类的初始化(Intialize):
            
    2.类加载顺序:
        1)先为 父类 类变量(static),分配空间,然后赋值。
        2)再为 子类 类变量(static),分配空间,然后赋值。
        3)开始创建对象,子类构造方法,为 子类 和 父类 本地变量分配内存地址,
        4)父类本地变量先赋值,在执行父类构造方法。
        5)子类本地变量先赋值,在执行子类构造方法。
        6)创建子类对象完毕。
        7)虚拟机会保证,类的初始化,在多线程环境下,被正确 加锁 和 同步
    3.类加载器(ClassLoader)的理解    
        1)ClassLoader:类加载器的作用,是把类(class文件),加载到内存中, 
        2)读取配置文件,可以使用流,也可以使用 类加载器 读取。
            示例:
                ClassLoader classLoader = ClassLoader_01.class.getClassLoader();
                InputStream ras = classLoader.getResourceAsStream("a.properties");
                            --目录默认为 :src 下
            相当于:
                FileInputStream fileInputStream1 = new FileInputStream(new File(""));


四:创建 运行时 类的对象
    1.根据字节码对象,创建对象
        Person person = Person.class.newInstance();
    2.本质:
        本质还是调用 Person 类的无参构造 方法。
        如需要创建成功:
            1)对象有无参构造方法
            2)无参构造方法,权限够。
    3.练习:写一个方法,传入字节码对象,创建对应的对象实例并返回。
    

五:获取 运行时 类的完整结构(获取私有的:Declared)
    1.获取类 结构信息
        1).获取所有属性:(包含父类)
            Field[] fields = Person.class.getFields();
        2).获取所有方法:(包含父类)
            Method[] methods = Person.class.getMethods();
        3).获取所有构造方法:(包含父类)
            Constructor<?>[] constructors = Person.class.getConstructors();
    2.所获得都是数组,可以使用 增强循环 遍历结果。
        每遍历一次,获得一个实例对象,在其中也可以获取信息。
    3.获取 Person 类,父类字节码对象
        Class<? super Person> superclass = Person.class.getSuperclass();
        Type genericSuperclass = Person.class.getGenericSuperclass();
    4.获取 类 的 接口,所在包,注解等。
六:调用 运行时 类的指定结构
    1.调用属性:
        Person person = Person.class.newInstance();
        Field age = Person.class.getDeclaredField("age");
        //为属性赋值
        age.set(person, 12);
        //获取属性值
        Object o = age.get(person);
    2.调用方法:
        1.普通方法:
            Class<Person> p = Person.class;
            Person person = p.newInstance();
            //获取指定方法                    -- 方法名    参数类型
            Method method = p.getDeclaredMethod( "setName" , String.class );
            //调用指定方法:    --person 调用对象。传入参数
            //invoke() 返回值就是,调用方法返回值。
            Object invoke = method.invoke( person , "123" );
            System.out.println( person.toString() );
        2.静态方法:
            Object o = method.invoke( Person.class , String.class );
        
    3.调用构造方法:
        Constructor<Person> dc = 
                Person.class.getDeclaredConstructor( String.class , Integer.class );
        Person zhangsan = dc.newInstance( "zhangsan" , 12 );
        
    4.调用时,碰见私有方法 
        clazz.setAccessible(true);


七:反射的应用:动态代理
    1. 静态代理:
        1)实现接口的静态代理,在调用方法前后,加上增强功能。
        2)特点:代理类 和 被代理类,在编译期间,就被确定下来。
    2.动态代理举例:
        1)用 反射 实现动态代理。
        2)
    3.反射的应用:AOP
    4.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值