反射-代理-注解——总结

反射

  • 认知:反射技术就是对类进行解剖,解剖出"构造器"、"成员变量"、"成员方法"
  • 构造器: 可以实例化对象
  • 成员变量:可以赋值、取值
    • 成员方法:调用方法
    • 大白话:不使用new关键字,可以实例化对象,可以访问对象中的成员
  • 反射技术,通常应用于:框架
  • 反射技术的程序书写步骤:
    1. 获取Class对象
    2. 获取构造器
    3. 获取成员(成员方法、成员变量)
    4. 实例化对象 | 调用方法 | 给成员变量赋值取值
  • 使用反射技术:
  • 核心点:Class类
  • Class类是什么呢?
  • JVM中只能执行.class字节码文件(Java程序中会存在大量的.class文件)
    • .class文件是通过类加载器读取到内存中,并基于这个.class文件创建出:Class对象
  • Class对象,就是指一个.class文件
  • Class类的作用
  • 通过Class对象,获取"构造器"、"成员方法"、"成员变量"
  • 步骤:
  • 1、获取Class对象
Class  cls = 类名.class;
Class  cls = 对象名.getClass(); 
Class  cls = Class.forName("类的全限定名");

//回顾:同步方法(线程), 非静态方法默认有一个同步锁:this   
//                     静态方法的同步锁:类名.class
      • 2、基于Class对象,可以获取:构造器、成员方法、成员变量
    • 构造器:Constructor类
Constructor c = Class对象.getConstructor();//无参构造器
Constructor c = Class对象.getConstructor(String.class);//有参构造器
        • 成员方法:Method类
Method m = Class对象.getMethod("方法名");//获取指定方法名的无参方法
Method m = Class对象.getMethod("方法名",int.class);
        • 成员变量:Field类
Field f = Class对象.getDeclaredField("属性名");

//针对私有成员:成员变量、成员方法、构造器,需要取消权限检查
f.setAccessible(true);//true就表示关闭本次权限检查
      • 3、使用构造器,调用newInstance(...)方法,来实例化对象
      • 4、使用成员方法,调用invoke(...)方法,来调用方法入栈执行
      • 5、使用成员变量,调用set(...)方法、get(...)方法,对变量进行赋值、取值

注解

  • 认知:
    • 注解单独使用,没有任何意义。
    • 通常注解会配合反射技术一起使用,常用于框架技术
  • 注解的定义:
public @interface 注解名{
    数据类型 属性名();
    数据类型 属性名() default 默认值;
    数据类型[] 属性名();
}

注解中的数据类型可以有哪些:
1. 8种基本数据类型
2. 枚举
3. String
4. Class
5. 注解
6. 以上所有类型的一维数组形式
  • 注解的使用:
@注解名
public class 类{

    @注解名(属性名=值)
    private String 成员变量;

    @注解名    //@Test
    public void 成员方法(int 参数){

                     }   
}
  • 元注解:
  • 作用:限定注解的使用位置、注解的生命周期
    • @Target //指定注解的使用位置
    • @Retention //设定注解的生命周期
    • SOURCE : 只能在源码中使用 。 例:@Override
    • CLASS :可以用于源码中、字节码文件中 【默认】
    • RUNTIME : 可以用于源码、字节码文件、程序运行 例:@Test
  • 注解解析(注解存在的意义)
注解解析的步骤:
1、获取一个对象(构造器Constructor、成员变量Field、成员方法Method)
2、判断对象上是否有指定的注解
有: 获取对象上的注解对象
对象上有注解后,获取注解对象中的属性值    

//API:
//判断某个对象(类、接口、成员变量、构造器、成员方法)上是否有使用注解
boolean flag = isAnnotationPresent(注解.class)//获取某个对象上的注解对象
注解名 对象 = getAnnotation(注解.class)

数据类型 变量 = 注解对象.属性;

  • 示例
//前置铺垫:
一张数据表   对应    类
一行记录     对应    对象    
一个字段     对应    成员变量

create table t_student
(
    sname varchar(20),
    sage  int
);

//类
class Student{
    private String name;
    private int age;
}
//JDBC程序: (程序员自己编写)
连接数据库
创建数据库操作对象
发送sql语句: select ...
处理结果集
 while(rs.next()){

    age = rs.getInt("sage");
    name =rs.getString("sname");

     Student stu = new Student();
     stu.setName( name );
     stu.setAge( age );
}
//框架技术: 反射+注解   (别人已经完成的)
//1、自定义一些注解
public @interface Entity{  //实体
String table();  //表名
}
public @interface property{ //属性
String name();
}
//2、解析@Entity、@Property注解
 扫描某些包下的的类,发现这些类上有@Entity、@Property注解,就会利用反射
 利用反射技术: 获取 Student.class 对象 (Class对象)
          解析 类上的@Entity注解
 利用反射技术: 获取所有的成员变量 : 
          解析所有成员变量上的@Property注解
//JDBC程序中使用框架技术中注解 ( 程序员自己编写 )@Entiry(table="t_student")  //表示当前的Student类和数据表t_student关联
class Student{
    @Property(name="sname") //表示当前的成员变量name和字段sname关联
private String name;

@Property(name="sage") //表示当前的成员变量age和字段sage关联
private int age;
}

动态代理

  • 动态代理,提供了一个代理的对象,有了代理对象后,当访问某个方法时,会被代理对象拦截(拦截后可以对方法进行前增强、后增强【代理对象不会破坏原有方法的代码】)
  • 动态代理的特点:
    • 动态的创建.class文件(创建一个和被代理类实现相同父接口的子类[代理类])
    • 动态的加载.class文件到内存中(创建Class对象)
      • Proxy类需要一个"类加载器"
    • 对程序员来讲,不需要书写代理类
  • 动态代理的代码实现:
代理对象 = Proxy.newProxyInstance(类加载器 , 父接口 , 处理器)
类加载器: 动态的加载.class文件

父接口 : 代理类和被代理类需要拥有共同的父接口

处理器: 代理对象拦截了方法后,对方法进行前增强、后增强,是由处理器来书写逻辑    
代理对象  = Proxy.newProxyInstance(
    类.class.getClassLoader(), //类加载器
    被代理类.class.getInterfaces(), //父接口

    new InvocationHandler(){
        public Object invoke(
            Object 代理对象, 
            Method 被拦截的方法对象 ,
            Object[] 方法中的实参
        ){




            //业务逻辑
        }

    }
)

动态代理:

  • 代理程序中的某个类中的功能,为该功能进行增强

动态代理实现的关键步骤:

  1. 被代理类(例:UserServiceImpl),必须有实现接口
  2. 创建被代理类对象(例: new UserServiceImpl() ),交给代理对象使用

动态代理的实现:

  • JDK已经提供了现成的代理对象的生成
  • Proxy类
  • 静态方法:newProxyInstance(类加载器 , 接口数组 , 处理器)
  • Proxy创建一个子类
  • 子类: 必须和被代理类实现相同的父接口
    • 子类编译后是一个.class文件, 需要使用类加载器,加载.class文件到内存中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值