part 1: 工作
具体内容:银行退单回购做修复、计算强云乌鲁木齐在贷
进度:已完成
领悟点:了解了在贷计算规则,总结为:先按照余额类型将在贷余额的发生额进行分类(通用逻辑),再按照在贷余额的生效日期将在贷余额的发生额进行分类(根据不同资方编写)。然后用两种分类的交集构成LoanBalance
part 2:学习内容
1. 反射:
1.1 class类:只有JVM能创建Class
实例,JVM持有的每个Class
实例都指向一个数据类型(class
或interface
)、一个Class
实例包含了该class
的所有完整信息
三种方法获取class类:
方法一:Class cls = String.class;
方法二:
String s = "Hello";
Class cls = s.getClass();
方法三:
Class cls = Class.forName("java.lang.String");
1.2 通过class类访问字段:
先获取field
- Field getField(name):根据字段名获取某个public的field(包括父类)
- Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
- Field[] getFields():获取所有public的field(包括父类)
- Field[] getDeclaredFields():获取当前类的所有field(不包括父类)
再通过field获取字段信息:getName()
,getType()
,getModifiers()
;
1.3 通过class类调用方法:
先获取method
Method getMethod(name, Class...)
:获取某个public
的Method
(包括父类)Method getDeclaredMethod(name, Class...)
:获取当前类的某个Method
(不包括父类)Method[] getMethods()
:获取所有public
的Method
(包括父类)Method[] getDeclaredMethods()
:获取当前类的所有Method
(不包括父类)
通过method获取一个方法的信息
getName()
:返回方法名称,例如:"getScore"
;getReturnType()
:返回方法返回值类型,也是一个Class实例,例如:String.class
;getParameterTypes()
:返回方法的参数类型,是一个Class数组,例如:{String.class, int.class}
;getModifiers()
:返回方法的修饰符,它是一个int
,不同的bit表示不同的含义。
使用反射调用方法时,仍然遵循多态原则:即总是调用实际类型的覆写方法(如果存在)
1.4 通过class类获取父类
Class i = Integer.class;
Class n = i.getSuperclass();
1.5 通过class类获取当前类实现的所有接口
Class[] getInterfaces()
2.注解
2.1注解的作用
从JVM的角度看,注解本身对代码逻辑没有任何影响,如何使用注解完全由工具决定。
Java的注解可以分为三类:
第一类是由编译器使用的注解,例如:
@Override
:让编译器检查该方法是否正确地实现了覆写;@SuppressWarnings
:告诉编译器忽略此处代码产生的警告。
这类注解不会被编译进入.class
文件,它们在编译后就被编译器扔掉了。
第二类是由工具处理.class
文件使用的注解,比如有些工具会在加载class的时候,对class做动态修改,实现一些特殊的功能。这类注解会被编译进入.class
文件,但加载结束后并不会存在于内存中。这类注解只被一些底层库使用,一般我们不必自己处理。
第三类是在程序运行期能够读取的注解,它们在加载后一直存在于JVM中,这也是最常用的注解。例如,一个配置了@PostConstruct
的方法会在调用构造方法后自动被调用(这是Java代码读取该注解实现的功能,JVM并不会识别该注解)。
2.2定义注解:
使用@Target
可以定义Annotation
能够被应用于源码的哪些位置:
- 类或接口:
ElementType.TYPE
; - 字段:
ElementType.FIELD
; - 方法:
ElementType.METHOD
; - 构造方法:
ElementType.CONSTRUCTOR
; - 方法参数:
ElementType.PARAMETER
元注解@Retention
定义了Annotation
的生命周期:
- 仅编译期:
RetentionPolicy.SOURCE
; - 仅class文件:
RetentionPolicy.CLASS
;(默认为CLASS)
- 运行期:
RetentionPolicy.RUNTIME
。
2.3使用和构造注解
使用反射API读取Annotation:
Class.getAnnotation(Class)
Field.getAnnotation(Class)
Method.getAnnotation(Class)
Constructor.getAnnotation(Class)
定义一个@Range
注解,String
字段长度满足@Range
的参数定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Range {
int min() default 0;
int max() default 255;
}
使用该注释
public class Person {
@Range(min=1, max=20)
public String name;
@Range(max=10)
public String city;
}
编写一个Person
实例的检查方法,它可以检查Person
实例的String
字段长度是否满足@Range
的定义:
void check(Person person) throws IllegalArgumentException, ReflectiveOperationException {
// 遍历所有Field:
for (Field field : person.getClass().getFields()) {
// 获取Field定义的@Range:
Range range = field.getAnnotation(Range.class);
// 如果@Range存在:
if (range != null) {
// 获取Field的值:
Object value = field.get(person);
// 如果值是String:
if (value instanceof String) {
String s = (String) value;
// 判断值是否满足@Range的min/max:
if (s.length() < range.min() || s.length() > range.max()) {
throw new IllegalArgumentException("Invalid field: " + field.getName());
}
}
}
}
}