zoukankan      html  css  js  c++  java
  • Bridge Method (桥接方法)

    在 @readThroughSingleCache 的实现 中有一个方法:

    final Method methodToCache = getCacheBase().getMethodToCache(pjp);

    作用是获取需要缓存的方法。

    具体如下:

    public Method getMethodToCache(final JoinPoint jp) throws NoSuchMethodException {
            final Signature sig = jp.getSignature();
            if (!(sig instanceof MethodSignature)) {
                throw new InvalidAnnotationException("This annotation is only valid on a method.");
            }
    
            final MethodSignature msig = (MethodSignature) sig;
            final Object target = jp.getTarget();
    
            // cannot use msig.getMethod() because it can return the method where annotation was declared i.e. method in
            // interface
    
            // 得到方法的名称和他的参数
            String name = msig.getName();
            Class<?>[] parameters = msig.getParameterTypes();
    
            Method method = findMethodFromTargetGivenNameAndParams(target, name, parameters);
    
            if (method.isBridge()) {
                if (getLogger().isDebugEnabled()) {
                    getLogger().debug("Method is bridge. Name {}, params: {}", name, parameters);
                }
    
                parameters = bridgeMethodMappingStore.getTargetParamsTypes(target.getClass(), name, parameters);
                method = findMethodFromTargetGivenNameAndParams(target, name, parameters);
            }
    
            return method;
        }

    这正好就用到了桥接方法。

    在jdk 1.5之前,还没有泛型,

    创建了一个集合对象,这时候什么样子的数据元素都可以放进去,用的时候再强制转换类型。编译器在编译期间是可以通过的,但是如果在运行时,转换类型不容许,那是会出错的。

    那在JDK 1.5 之后引入了泛型。 使用者可以定义集合的类型。这时候就必须是自己定义的类型集合,你定义的String类型的,而你又想加入Integer的元素是不容许的。这样的话,就在编译器编译检查这钟情况了。

    问题来了,如何兼容JDK 1.5 前后这种情况呢? 就是说编译器现在编译期间都提示这种错误了

    举例说明:

      abstract class A<T> {  
      abstract T get(T t);  
      }  
      
      class B extends A<String> {  
      @Override
          String get(String s) {  
      return "";  
          }  
      }  
      
      public class TestBridge {  
      public static void main(String[] args) {  
              Class<B> clazz = B.class;  
              Method[] methods = clazz.getDeclaredMethods();  
      for (int i = 0; i < methods.length; i++) {  
                  Method m = methods[i];  
                  System.out.println(getMethodInfo(m) + " is Bridge Method? " + m.isBridge());  
              }  
          }  
      
      public static String getMethodInfo(Method m){  
              StringBuilder sb = new StringBuilder();  
              sb.append(m.getReturnType()).append(" ");  
              sb.append(m.getName());  
              Class[]params = m.getParameterTypes();  
      for (int i = 0; i < params.length; i++) {  
                  sb.append(params[i].getName()).append(" ");  
              }  
      return sb.toString();  
          }  
      }

    运行这段代码,可以看到的结果:

    [class java.lang.String get] is Bridge Method? false 
    [class java.lang.Object get] is Bridge Method? true

    奇怪吧,有两个方法了,明明我只写了一个方法啊!!

    下面来说说java5编译器是如何来编译上面的代码:

    Java代码  
    
    abstract class A<T> {  
    abstract T get(T t);  
    }

    对于A类,编译器看到<>中指定的T参数后,会用Object把类中的其他T参数替换。因为在jdk中根本就不存在T这个类嘛。替换后就成了下面这样子。

    Java代码  
    
    abstract class A {  
    abstract Object get(Object obj);  
    }

    上面这个过程称为类型擦除。对于B类,它继承了A类,指定了T参数为String。如果还按照以前那么编译,那编译的类就是:

    Java代码  
    
    class B extends A {  
        String get(String s) {  
    return "";  
        }  
    }

    这样在运行时肯定会报错,因为B继承了A,而A又是asbtract类,B还没overriding A中Object get()方法。如何解决这个错误呢?java5编译器在编译的时候做了些手脚。当编译器发现你指定了类型参数,便会在编译的字节码中添加一个桥接方法。这个可以查看B的反编译代码就知道了。

    Java代码  
    
    class B extends A {  
    //编译器添加的方法
        Object get(Object s) {  
    return (Object) get((String) s);  
        }  
    
        String get(String s) {  
    return "";  
        }  
    }

    对了,就是 在B类中编辑器给新增了一个方法。

    桥接方法: 就是连接两个东西的方法。

    这个方法可以用于为了升级所带来的不兼容问题。

  • 相关阅读:
    DataTable 类(二)处理表中的数据
    .NET中的正则表达式
    DataTable 类(一)表结果操作
    DataGridView(2)数据操作
    DataGridView(一)
    VS2008中配置 Windows SDK v7
    TabControl
    .NET中的正则表达式 (一)Regex 类
    db2的count()函数和sum()函数的用法
    显示原始字符串
  • 原文地址:https://www.cnblogs.com/pan2011/p/3650318.html
Copyright © 2011-2022 走看看