作为一个工作了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 function=input->new Reflector(input);
*/
}
public static void method(String s, Function 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
*
*/
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 ageList;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getAgeList() {
return ageList;
}
public void setAgeList(List ageList) {
this.ageList = ageList;
}
}
static class ReturnTypeTest {
T ageInfo;
}
}