Java的Reflection和后绑定

     这个主题本身是一个比较advanced的话题,这里只谈一下我的粗浅理解,还请各位能补充。
    
     绑定是指将方法和调用方法的对象(或类)绑定,而后绑定是指绑定发生在运行时刻而非编译时刻。事实上,大多术面向过程的语言,比如c只支持前绑定,即绑定发生在编译时。
     我们先来举一个例子:
     interface Fly {
           public void fly();
     }
     class bird implements Fly{
           public void fly(){
                 System.out.println("bird fly!");
           }
     }
     class plane implements fly{
           public void fly(){
                 System.out.println("plane fly!");
           }
     }
     class FlyFactory {
            private static FlyFactory myself; 
            private FlyFactory();
            public Fly getFly(){
                 return new bird();
            }
            public Fly getAnotherFly(){
                 return new plane();
            }
            public static getInstance(){
                 if (myself == nul){
                       myself = new FlyFactory();
                 }
                 return myself
            }l
     }
     public class Binding {
           public static void main(String[] args){
                 Fly FirstFly =  FlyFactory.getInstance().getFly();
                 Fly SecondFly = FlyFactory.getInstance().getAnotherFly();
                 FirstFly.fly();
                 SecondFly.fly();
            }
     } 
     很明显,main跑起来后显示的是
     bird fly!
     plane fly!
     有些人就会问了,申明的都是Fly接口,那么虚拟机究竟是怎么知道实际调用的到底是哪个实现呢?  这就是后绑定!完全在运行时刻和具体的实例绑定!(上述采用了factory method这种设计模式,而FlyFactory本身又采用了singleton模式,有兴趣的人可以琢磨一下) 
     实现后绑定的技术称作RTTI(run-time type identification)运行时类型检查。Java 的RTTI有三种:
     一种是在形式上是传统的所谓强制类型转换,即在实例之前加上想要转换的类型并用括号括起来。这在c/c++里面很常见,但是c/c++这种形式是不采用RTTI形式的,所以称为“强制”!即不做类型检查,所以是不安全的类型转换,即你永远无法预计会产生什么结果。但是java将这种形式做了RTTI检查,即如果在运行时发现类型转换出错,会抛出ClassCastException,所以是类型安全的!
      一种就是Reflection(反射),以下会重点介绍,因为反射使后绑定完全成为运行时的工作了,是实现多态的坚固的技术后盾。
      最后是instance of 操作符,在这篇日志中就不做介绍了。
      现在就让我们来谈谈反射,事实上上述的例子用的就是反射,通过反射来具体知道方法究竟是属于哪一个实例的!也许你已经想到,想要完全在运行时刻(即在代码里完全不做类型转换的显示申明)jvm必须得到额外的关于这个实例的类型信息,或者称为元数据 (meta data)。
      这个类型信息就是隐藏在每个类里面的class成员变量。这个变量并不是你自己加在代码里的而是java自动帮你加入的。拿上述的Fly接口来说他就有一个class成员变量,而这个成员变量提供许多得到该类类型信息的方法,包括他是不是个接口,他的父类,他的方法等等。而对于实例你可以调用getClass()方法得到这个class变量。因此jvm就是查看每个实例和类里的这个class成员变量的一些信息来进行后绑定的!
      最后介绍反射的另一个用法。有jdbc开发基础的人都对这个方法很熟悉class.forName(),参数往往是驱动名称(即带包结构的类名)。class.forName就是利用反射技术告诉ClassLoader去动态加载参数所表示的那个类!注意只是加载,如果你还要得到实例的话那么必须调用class.forName(ClassName).newInstance()前提是该类有无参数的构造函数!也许你要问为什么要这样做,直接申明一个实例不是更好吗?我之前的那篇谈接口和抽象类的日志里提到过可插拔的技术。可插拔就是脱离硬编码(hard coding)完全能在不重新编译代码的情况下,换一个实现。而反射就是实现这种方式的技术后盾。我可以把要用的实现的类名放在一个配置文件中,然后去读这个配置文件,那在程序中,内容肯定是放在一个输入流中,假设叫in,那么你就可以通过调用class.forName(in.toString()).newInstance()来产生实例,而完全不用管留里面究竟是什么了,这通过常规的生成实例是不可能完成的,因为常规的方法需要知道类名,换类名就要改代码,这就变成了硬编码了。但是通过反射,我只需要换那个配置文件,而把程序重启以下就行了!
      以上就是我个人对反射和后绑定的理解,希望大家能够补充,另外这篇日志的代码实例所采用的两种设计模式,需要的人可以参看一下!
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值