大龄菜鸟-》 mybatis 源码阅读-》 reflection 反射模块

作为一个工作了7年的大龄女码农,老实说,我一直没有看过什么源代码。迫于对前途的迷茫。我想改变现状。想做些和之前工作几年不一样的事。

看源代码的出发点,想看大神的代码是怎么写的,想知道别人是怎么想的。然后再反思下,如果是自己,自己怎么想。

之前在培训学校老师告诉我们csdn是开发者交流最好的网站。在此,在我启蒙和学习的网站。我立个flag。我要把我用到的源代码,在这个上面进行更新。可能还没更新完我转行了也不一定,但是我就是想做个事。

不给任何人证明。只是想善始善终。对过去有交代。原来我可以输出和沉淀点东西。

一:下面是mybatis包的目录,我们今天的主角是reflection包。

二: 这个反射包,我看下来,最重要的是下面这些类,我把重点方法,列了下。Reflector 反射器是底层处理反射的。这个图有的类列的方法不是最全。我只挑重点的列。

 

从上面图可以看出来。MetaObject的控制基本都是交给了ObjectWrapper进行控制的。ObjectWrapper中对类的控制依赖于MetaClass类,MetaClass 类中依赖 ReflectorFactory 和Reflector。

上面这些是拿最简单的属性来说没。当属性是下面这个样子的时候,会进行分词,那么上面getValue和setValue会进入递归循环。大家可以自己测下。

 @Test
  void shouldGetAndSetNestedProperty() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richProperty", "foo");
    assertEquals("foo", meta.getValue("richType.richProperty"));
  }
三: MetaObject 对象的 setValue 和 getValue 里面用了递归,递归的控制是由分词器PropertyTokenizer 来控制结束的。里面有单测类,强烈建议运行下单测看数据。就能理解我为啥说setValue 难。为啥麻烦。

分词器PropertyTokenizer在反射包出现的概率特别的高。

四: PropertyTokenizer 分析如下图。

 

五: 今天是分析的第一天。我自己看第一遍,可能自己能理解到个七八层,表达起来也许大家看起来不生动。写的不好的地方,多包涵。下面我上单测和一步一步加注释的源代码

尴尬,文章中不允许上代码包。我把代码放到了我的资源文件中。资源文件中大家可以下载,不需要积分。https://download.csdn.net/download/lileronglilerong/15120273

六: 额外补充下

a:  看上面代码我遇到有些不懂的写法。自己理解了下。关于function

package com.llr.reflect.test;

import java.util.function.Function;

public class FunctionTest {
    public static void main(String[] args) {
        String s="1234";
       /* method(s,(String inputValue)->{
            return  Integer.parseInt(inputValue);
        });*/
       // 这个写法和上面的是一样的
        method(s, Integer::parseInt);
        /**
         *    Reflector::new 等价于下面的表达式
         *    Function<Class,Reflector> function=input->new Reflector(input);
         */
    }

    public static void method(String s, Function<String,Integer> function){
        Integer i=function.apply(s);
        System.out.println(i);
    }
}

b: computeIfAbsent  和 isAssignableFrom

package com.llr.reflect.test;

import java.util.HashMap;

public class MapTest {
    public static void main(String[] args) {
        /**
         * 1: computeIfAbsent的方法
         * computeIfAbsent的方法有两个参数 第一个是所选map的key,第二个是需要做的操作。这个方法当key值不存在时才起作用
         */
        HashMap map=new HashMap();
        // java8之前。从map中根据key获取value操作可能会有下面的操作
        Object value = map.get("key");
        if (value == null) {
            value = new Object();
            map.put("key", value);
        }
        // java8之后。上面的操作可以简化为一行,若key对应的value为空,会将第二个参数的返回值存入并返回
        Object key2 = map.computeIfAbsent("key", k -> new Object());


        /**
         * 2:isAssignableFrom (is Assignable(可分配))    instanceof
         *
         * ClassA.isAssignableFrom(ClassB); 表示ClassA是ClassB父类就返回true,否则返回false
         *
         *  父类.class.isAssignableFrom(子类.class)
         *  子类实例 instanceof 父类类型
         */
    }
}

c:  什么是实例?

package com.llr.reflect.test;

public class BaseTest {
    public static void main(String[] args) {
        /**
         * 1: 什么是java的实例,什么是引用,什么是引用地址,什么是内存地址。
         *
         * Cat c 的意思是,在内存中分配一个变量,名字叫c,这个变量是Cat类型的
         *
         * new Cat(); 说明 new这个Cat类的一个对象,程序运行的时候,会调用构造方法Cat(),等这个构造方法执行完了,这个Cat类型的对象也就造出来了,真正的出现在内存当中了
         *
         * c就是引用,不是对象!我们new出来的这个东西,真正在内存中的这个东西叫做对象,叫做实例.
         */
        Cat c = new Cat();
        /**
         *
         * 2: 单例模式 和 静态方法。
         *
         * 这个怎么区分,如何进行使用。
         *
         * 目标:
         * a: 弄明白什么是单例模式,什么是 静态方法。
         * b: 弄明白二者的区别。
         * c: 弄明白适合的场景
         *
         * 静态方法和非静态方法:
         * 一: 静态方法和非静态方法。他们都是在第一次加载后就常驻内存
         * 二:
         * 在内存中的区别,非静态方法,创建实例对象的时候,因为属性的值对于每个对象不同,故new一个实例的时候,会把
         * 实例属性在GC heap 里copy一份,同时这个new出来的对象放在堆栈上,堆栈指针指向了刚才拷贝的那一份实例的内存地址上。
         * 而静态方法不需要。因为静态方法里面的静态字段,就是保存再 method table 里的,就只有一份。
         *
         * 三: 早期几乎所有方法都是“静态方法”,引入实例化方法概念是面向对象概念出险以后的事情。
         *
         * 结论:静态方法和实例方法是为了解决模式问题。 如果一个方法和他所在类的实例对象无关,那么他应该是静态的。否则应该是非静态的,像工具类,一般都是静态的
         *
         * 为什么使用单例模式而不用静态方法?
         * 如果一个方法和他所在类的实例对象无关,那么他应该是静态的,反之他就应该是非静态的,如果我们确实应该使用非静态的
         * 方法,但是在创建类时又确实只需要维护一份实例时,就需要用单例模式。
         *
         */
    }

    static class Cat{
        public Cat() {
        }
    }
}

d:

Class 类中的部分方法和Method类中部分方法,还有喔。看 ParamNameUtil  这个方法的时候,我第一次发现

Executable 类是 :方法和Constructor的共同功能的共享超类 
package com.llr.reflect.test;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

public class MethodTest {
    public static void main(String[] args) {

        try {
            /**
             * 1:  Class 类中的 区别是什么:getMethod,getDeclaredMethod
             */
            Class studentClass = Student.class;
            // Member  接口中的 PUBLIC和 DECLARED就有对应的描述
            // getMethod 返回所有公用的(public) 包括继承的, 如果 getName 给的是private的话,是会报错的。
            Method getNameMethod = studentClass.getMethod("getName");
            // getDeclaredMethod 返回包括公用的,私有的,默认的,但是不包括继承的
            Method setNameMethod = studentClass.getDeclaredMethod("setName", String.class);
            System.out.println(getNameMethod.getName());
            System.out.println(setNameMethod.getName());

            /**
             *
             * 2:  getDeclaringClass 和 getClass区别
             * getDeclaringClass
             * 返回的是 (返回 类表示声明该对象表示的可执行的类或接口对象。 )
             * class com.llr.reflect.test.MethodTest$Student
             *
             * getClass: (返回此Object的运行时类。 返回的类对象是被表示类的static synchronized方法锁定的对象。 )
             * 返回的是:class java.lang.reflect.Method
             */
            System.out.println("+++++++++++++++++");
            System.out.println(getNameMethod.getDeclaringClass());
            System.out.println(getNameMethod.getClass());

            /**
             * 3: getParameterTypes和getGenericParameterTypes区别
             *
             * getParameterTypes 无法取到对象中是泛型的结构化参数。 setAgeList:List
             * getGenericParameterTypes 可以取到对象中泛型的结构化参数。 setAgeList:java.util.List<java.lang.Integer>
             *
             */
            System.out.println("+++++++++++++++++");
            Method[] methods = studentClass.getMethods();
            Arrays.stream(methods).forEach(method -> {
                Class[] pType = method.getParameterTypes();
                Type[] gPType = method.getGenericParameterTypes();
                if (method.getName().contains("setAgeList")) {
                    for (Class aClass : pType) {
                        System.out.println(method.getName() + ":" + aClass.getSimpleName());
                    }
                    for (Type type : gPType) {
                        System.out.println(method.getName() + ":" + type.getTypeName());
                    }
                }
            });
            System.out.println("+++++++++++++++++");

            /**
             * 2: Method   中的getGenericReturnType和getType的区别,
             *
             * Class 实现了 Type 接口。Type 是更上层的接口
             *
             * getType 输出 class java.lang.Object,而 getGenericType 输出的是 T。
             *
             * 如果 getGenericSignature 不为空,即如果当前类型是泛型,则返回泛型类型,反之返回 getType() 的值
             */
            Class getAge = ReturnTypeTest.class.getDeclaredFields()[0].getType();
            Type getGenericAge = ReturnTypeTest.class.getDeclaredFields()[0].getGenericType();
            System.out.println(getAge.getSimpleName());
            System.out.println(getGenericAge.getTypeName());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }


    static class Student {
        private String name;
        private List<Integer> ageList;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public List<Integer> getAgeList() {
            return ageList;
        }

        public void setAgeList(List<Integer> ageList) {
            this.ageList = ageList;
        }
    }

    static class ReturnTypeTest<T> {
        T ageInfo;
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值