Java反射机制和动态代理

前言:

反射机制是java的高级特性之一,而且也是基础,那么反射有什么应用场景呢,当然平常写业务逻辑开发一般是用不到的,它的应用是在框架里面,所以看源码,学习框架不懂这个代码都看不懂,所以还是要掌握它。

反射是什么?

java反射是在运行状态下,对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法和属性,这种动态获取信息以及动态调用队形的功能成为java语言的反射机制。

Class

  • 提到反射就不能不提Class了,Class可以说是反射能够实现的基础,这里说的Class和class关键字不是一个东西,class关键字是在声明一个java类的时候用的,而Class是javaJDK提供的一个类

  • 对于每一个类,Java虚拟机都会初始化一个Class类型的实例,每当我们编写并且编译一个新创建的类就会产生一个对象的Class对象,并且这个Class对象会被报存到同名的.class文件中,当我们new出一个实例或者引用静态变量时,Java虚拟机中类加载器会将对应的Class对象加载到JVM中,然后JVM会根据这个类型信息的Class对象来创建我们需要的实力对象或者提供静态变量的引用值。

类的结构信息组成

  • AnnotatedElement接口:该接口提供了获取注解信息的一些方法,即所有的参数、方法成员变量、构造方法都能通过反射获取到注解的相关信息

  • package类:对应Java包 的一些信息。

  • Parameter类:对应构造方法或者成员方法的参数类型,如参数访问限制,参数类型等

  • AccessibleObject类:该类是成员变量。成员方法、构造方法的父类。提供了一些public private等修饰符的入口检查

  • GenericDeclaration类:提供泛型的一些信息

  • Field类:对应的是成员变量

  • Executable类:可执行的、由两个子类、成员方法和构造方法,提供了两种方法公共的必要进行的一些操作,比如获取方法参数、获取方法名称、获取方法访问修饰符等等。

  • Method类:对应方法的类,提供了累的一些方法信息

  • Constructor类:对应构造方法的类,提供了构造方法的一些信息

  • Class类:包含了类的所有信息

    一般我们常用的一般都是Field、Method Constructor这三个类

反射的使用

获取到java中要反射类的字节码有三种方法
  1. 任意一个类都有一个隐士的静态成员变量class
    Class c=Statudent.class;
    
  2. 通过getClass方法获得
    Class c2=mStatudent.getClass();
    
  3. 通过Class.forname();
    Class c=Class.forName("包名+类名");
    
得到Class对象 我们就可以获取这个类中任意一个方法或者属性
  1. 获取该类中指定的属性
    Class<?> studentClass=student.getClass();
    Fiele ageField=studentClass.getDeclaredField("age);
    ageField.setAccessible(true);
    System.out.println("student的年龄"+student.getAge());                               
    
  2. 获取类中所有的字段包括父类的
    Class<?> studentClass=student.getClass();
    Field[] fieldArray=studentClass.getFields();
    for(int i=-;i<fieldArray.length();i++){
        System.out.println("当前方法名字是"+fieldArray[i]);
    }
    
  3. 获取该类所有的字段不包括父类的
    Class<?> studentClass=student.getClass();
    Field[] fieldArray=studentClass.getDeclaredFields();//主要是这个方法的区别
    for(int i=-;i<fieldArray.length();i++){
        System.out.println("当前方法名字是"+fieldArray[i]);
    }
    
  4. 修改非静态的方法和属性需要一个要修改的类的对象
    Student student=new Student(20);
    Class<?> studentClass=student.getClass();
    Field ageField=studentClass.getDeclaredField("age);
    ageField.setAccessible(trye);
    ageField.set(student,30);
    System.out.println("当前学生通过反射修改后的年龄是"+student.getAge());
    

    上面需要注意的是如果字段是非public的 需要在访问该字段之前设置setAccessible(true),那么对于一个final字段是否可以通过反射修改它的值呢,答案是肯定的,前提是在访问该字段之前要取消该字段的访问权限,但是如果该字段即被static修饰又被final修饰,那么是无法修改的。

  5. 修改静态的字段

    和修改非静态字段相比,修改类的静态字段就要轻松的多,因为静态字段是属于类所有的,所以在修改静态字段的时候就不需要在传递一个该类的实例对象了

    Field nameField=studentClass.getDeclaredField("name);
    nameField.setAccessible(true);
    nameField.set(null,"demo");
    System.out.println("反射修改静态字段  修改的名字是"+nameField.get(null));
    
通过反射获取并且调用类中的方法

Class类提供了4中方式获取类中的方法,其实和获取Field一样

  1. getMethod(String name,Class[] params) 使用特定的参数类型,获得name名字相同的公共方法
  2. Method[] getMethods() 获取类的所有公共方法 有父类的
  3. Method getDeclaredMethod(String name,Class[] params);可以获取私有的方法通过特定的参数类型。
  4. Method[] getDeclaredMethods() 获得类声明的所有方法 不包括父类的

和前面设置属性一样,method 有invoke(Object obj,Object ...args)这个方法,通过这个方法,可以调用任意一个类的任意一个方法,当然 如果要是调用的静态方法,那么第一个参数就直接填null。

反射机制的优缺点

  • 优点:就是可以实现动态创建对象和编译,强大的灵活性,并且代码简洁明了,
  • 缺点:对性能有影响,使用反射是一种解释操作,而且还绕过了源码,会干扰原来的内部逻辑

代理

代理是一种常见的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问,代理类负责委托类预处理,以及进行被委托类执行后的处理。

如果需要委托类来处理某一个业务,那么我就可以先在代理类中统一处理然后在调用具体实现类。

分类:
  1. 静态代理:由开发人员创建代理类,在对其进行编译,代理类内部是持有真实类的对象的。在程序运行钱代理类的.class文件就已经存在了
  2. 动态代理:在程序运行时使用反射机制动态创建一个代理类。根据jdk的源码可以看到
动态代理:
//先定义接口
interface Subject{
    void say(String name);
}

//这是真实处理对象
class RealSubject implements Subject{
    
    public void say(String name){
        System.out.println("我的姓名是"+name);
    }
}
//下面是一个动态代理类,

class CustomInvocationHandler implements Invocationhandler{
    
    Object  subObj;
    public CustomInvocationHandler(Object obj){
        this.subObj=obj;
    }
    
    public Object getProxyInstance(){
        rerutn Proxy.newProxyInstance(subObj.getClass.getClassLoader(),subObj.getClass.getInterfaces,this);
    }
    
    public Object invoke(Object proxy,Method method,Object[] args){
       return method.invoke(subObj,args);
    }
}


//   下面开始使用动态代理类
RealSubject realObj=new RealSubject();
CustomInvocationHandler mInvocation=new CustomInvocationHandler(realObj);
Subject proxyObj=mInvocation.getProxyInstance();//得到代理对象 转成 
proxyObj.say();

jdk中生成动态代理的源码:

ProxyUtils.generateClassFile(aafactory.getClass(),employee1.getClass().getSimpleName();ProxyUtils.generateClassFile(bbToolsFactory.getClass(),employee2.getClass().getSimpleName());
Method[] methods = aafactory.getClass().getMethods();
for(Method method:methods) {
  System.out.println(method.getName());//打印方法名称
 }
public class ProxyUtils {

    public static void generateClassFile(Class clazz,String proxyName){
        /*ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);*/
        byte[] proxyClassFile =ProxyGenerator.generateProxyClass(
                proxyName, new Class[]{clazz});
        String paths = clazz.getResource(".").getPath();
        System.out.println(paths);
        FileOutputStream out = null;

        try {
            out = new FileOutputStream(paths+proxyName+".class");
            out.write(proxyClassFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容