首先我得先请大家不要误会,博客园说转载的文章放在文章分类里,原创的文章用随笔写,我开先还以为随笔是拿来写抒情文的(滑稽),后来才发现不是这样的,但是自己所有的文章都在文章分类里了,又懒得搬运,所以我就用js重定向了一下。所以现在标题栏里进来的都是文章分类哦,大部分都是自己原创的,转载会注明转载的url。

废话不多说,今天我想来聊一下java里的反射和动态代理的问题,因为这两个东西实在撩人,而且动态代理百度几乎都是千篇一律,今天我写这篇博文希望能帮助大家,顺便也是为了巩固自己,毕竟自己也折腾了好久。

先来看看反射。

java里的class文件加载分为两种情况,一种就是类型是编译器已知的,这种文件的.class文件在编译的时候,编译器会把.class文件打开检查,但是注意不是加载哦,第二种就是我们可能是从别的地方获取到了一个引用,然后动态的把这个未知类型的引用的对象的.class文件加载进jvm虚拟机里。

那么我们称前者为RTTI,即Run- Time Type Identification 运行时类型识别,有的人把RTTI翻译成 Run - Time Type Information ,我个人认为是不对的,因为我觉得它概括的不够全面,所以我建议大家把I 翻译成Identification更容易理解。

我们称后者为“反射”,这对于正在学习JAVA的人来说可是一个新的名词,但反射也是作为一个java的核心技术的存在。下面就来看看反射究竟有多重要吧。

反射

在java里提供了一个叫做reflect的库,这个库里封装了Method,Constructor,field,Proxy,InvocationHandler 等类,这些类的API在我们学习反射会很有帮助。

反射最大的作用就在于我们可以不在编译时知道某个对象的类型,而在运行时得到。同时我们只需要得到我们想得到的类的名字即可(如果不在一个包,必须写完整的名字包括包名)。

package com.bike;

import java.lang.reflect.*;

public class Main {
public static void main(String[] args) throws Exception{
//返回A的构造方法
Constructor c = A.class.getConstructor();
//返回A类的所有为public 声明的构造方法
Constructor[] cons = A.class.getConstructors();
//返回A类所有的构造方法,包括private
Constructor[] cons2 = A.class.getDeclaredConstructors();
//返回A类的第一个public 方法
Method m = A.class.getMethod("say");
//执行
m.invoke(A.class.newInstance(), null);
//返回A类所有的public 方法
Method[] ms = A.class.getMethods();
//返回A类所有的方法,包括private
Method[] allMs = A.class.getDeclaredMethods();
//返回A类的public字段
Field field = A.class.getField("i");
System.out.println(field.get(A.class.newInstance()));
//返回A类的static 字段
System.out.println(field.get(null));
}
} class A{
public int i = 1;
public static int b = 2;
public A(){
System.out.println("无参构造");
}
private A(String s){
System.out.println("有参构造"+s);
} public void say(){
System.out.println("say");
}
}

这里我只是简单的把API罗列了一下,大家可以自己动手试试,我这里就不再去描述了。

通过上面的例子我们可以看出我们只用知道一个类的名字便可以得知它内部方法和字段,那么这里已经强烈的体现到了反射的作用。只是我这里做例子的时候把A作为了自己内部包的一个类,而在实际开发中,你可能是跨包的,所以你必须要写上全名才行。

关于.class类字面常量的知识请参照我的上一篇博文:http://www.cnblogs.com/haodawang/articles/5954368.html

代理

接下来我们来看一下代理。

代理可以帮助我们进行很好的封装,使底层的代码能够有效的隐藏起来。

为了区别,我们先来看看静态代理吧。


public class Main2 {
//这里传入的是接口类型的对象,方便向上转型,实现多态
public static void consumer(ProxyInterface pi){
pi.say();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
consumer(new ProxyObject());
}
} //代理接口
interface ProxyInterface{
public void say();
} //被代理者
class RealObject implements ProxyInterface{
//实现接口方法
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("say");
} } //代理者
class ProxyObject implements ProxyInterface{ @Override
public void say() {
// TODO Auto-generated method stub
//dosomething for example
System.out.println("hello proxy");
new RealObject().say();
System.out.println("this is method end");
} }
output:
hello proxy
say
this is method end

这就是静态代理,理解这个应该不难。

下面我们再来看看动态代理

import java.lang.reflect.*;

public class Main {
static void customer(ProxyInterface pi){
pi.say();
}
public static void main(String[] args){
RealObject real = new RealObject();
ProxyInterface proxy = (ProxyInterface)Proxy.newProxyInstance(ProxyInterface.class.getClassLoader(),new Class[]{ProxyInterface.class}, new ProxyObject(real));
customer(proxy);
}
} interface ProxyInterface{
void say();
} //被代理类
class RealObject implements ProxyInterface{
public void say(){
System.out.println("i'm talking");
}
} //代理类,实现InvocationHandler 接口
class ProxyObject implements InvocationHandler{
private Object proxied = null;
public ProxyObject(){ }
public ProxyObject(Object proxied){
this.proxied = proxied;
}
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
System.out.println("hello");
return arg1.invoke(proxied, arg2);
};
}

可以看到动态代理的代理类是实现了一个InvocationHandler的接口,我们通过reflect.Proxy的类的newProxyInstance方法就可以得到这个接口的实例,然后再来作为参数传递进去,这里每一个在代理类上处理的东西也会被重定向到调用处理器上。

至于动态代理和静态代理的区别,即动态代理是动态的创建代理和动态的处理方法的,这也是反射的一个重要体现之处。

Java动态代理与反射详解的更多相关文章

  1. 5.java动态代理、反射

    1.java动态代理.反射(IDEA导入JUnit4) 1.1.反射 通过反射的方式可以获取class对象中的属性.方法.构造函数等 1.2.反射代码 import java.io.Serializa ...

  2. Java 动态代理与反射机制

    java动态代理必须的两个类与两个接口: 首先需要有一个接口(委托者需要实现该接口的方法)示例如下: <pre name="code" class="html&qu ...

  3. Java基础13:反射详解

    本节主要介绍Java反射的原理,使用方法以及相关的技术细节,并且介绍了关于Class类,注解等内容. 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech ...

  4. Java动态代理和反射机制

    反射机制 Java语言提供的一种基础功能,通过反射,我们可以操作这个类或对象,比如获取这个类中的方法.属性和构造方法等. 动态代理:分为JDK动态代理.cglib动态代理(spring中的动态代理). ...

  5. Mybatis mapper动态代理的原理详解

    在开始动态代理的原理讲解以前,我们先看一下集成mybatis以后dao层不使用动态代理以及使用动态代理的两种实现方式,通过对比我们自己实现dao层接口以及mybatis动态代理可以更加直观的展现出my ...

  6. 详解java动态代理机制以及使用场景

    详解java动态代理机制以及使用场景 https://blog.csdn.net/u011784767/article/details/78281384 深入理解java动态代理的实现机制 https ...

  7. JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解

    在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...

  8. JAVA动态代理详解

    1.什么是代理 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 2.什么是动态代理 在程 ...

  9. java动态代理使用详解

    我们都知道AOP的原理就是java的动态代理机制,下面我就对java的动态代理机制进行学习与总结 java动态代理的实现有两个重要的类: Proxy:类 作用就是用来动态创建一个代理对象的类 Invo ...

随机推荐

  1. [Web安全] XXE漏洞攻防学习(中)

    0x00.XXE漏洞攻击实例 攻击思路: 1. 引用外部实体远程文件读取 2. Blind XXE 3. Dos 0x01.外部实体引用,有回显 实验操作平台:bWAPP平台上的XXE题目 题目: 进 ...

  2. BZOJ.4727.[POI2017]Turysta(哈密顿路径/回路 竞赛图)

    题目链接 \(Description\) 给出一个n个点的有向图,任意两个点之间有且仅一条有向边.对于每个点v,求出从v出发的一条经过点数最多,且没有重复经过同一个点一次以上的简单路径. n<= ...

  3. 5.27 Test

    1.COGS.2039. 树的统计 思路: 各种方法. 代码: 1.遍历树1   时间 0.314 s   平均内存 2.96 MB #include<cstdio> using name ...

  4. 二分图带权匹配 KM算法与费用流模型建立

    [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和最大或最小.而二分图的最佳匹配则一定为完备匹配,在此基础上,才要求匹配的边权值之和最大 ...

  5. BZOJ2759一个动态树好题 LCT

    题如其名啊 昨天晚上写了一发忘保存 只好今天又码一遍了 将题目中怕$p[i]$看做$i$的$father$ 可以发现每个联通块都是一个基环树 我们对每个基环删掉环上一条边 就可以得到一个森林了 可以用 ...

  6. 喵哈哈村的魔法考试 Round #17 题解

    喵哈哈村的秘境探险系列. A. 实际上就是求乘积%k是否等于0,显然 a * b % k = (a%k)*(b%k)%k,所以边乘边取模就好了. #include<bits/stdc++.h&g ...

  7. Pycharm中实现多个项目共存的方式

    一.背景 在Python学习中,使用pycharm只能打开一个项目,如果想在一个pycharm中同时打开多个项目,该怎么办呢?由于学习中遇到需要打开多个项目,所以就百度查询了一下方法. 二.解决办法 ...

  8. A - K进制下的大数

    https://vjudge.net/contest/218366#problem/A 中间溢出,注意求模. #include<iostream> #include<cstdio&g ...

  9. CentOS 7卸载Docker

    1.先查询所有安装的包 yum list installed | grep docker*或者rpm -qa docker* 2.删除查询出来的包 # 一般情况会有一个 yum remove -y d ...

  10. DIY自己的AllocateHWnd函数

    Classes单元的AllocateHWnd函数是需要传入一个处理消息的类的方法的作为参数的,原型: function AllocateHWnd(Method: TWndMethod): HWND; ...