0%

一个ORM例子

定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field {
String colName();
String type();
int length();
}

实体类

1
2
3
4
5
6
7
8
9
@Table("user")
class User {
@Field(colName = "user_id", type = "int", length = 10)
private int id;
@Field(colName = "user_name", type = "varchar", length = 10)
private String name;
@Field(colName = "user_password", type = "varchar", length = 64)
private String password;
}

获取注解进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ReflectAnno {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
Class<User> c = User.class;

// 获得类上的注解
Annotation[] annotations = c.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("annotation = " + annotation);
}

// 获取注解的值
Table target = c.getAnnotation(Table.class);
System.out.println(target.value());

// 获取类的Field
java.lang.reflect.Field name = c.getDeclaredField("name");
// 获取Field上的注解
Field nameAnnotation = name.getAnnotation(Field.class);
// 获取注解的值
System.out.println("nameAnnotation.colName() = " + nameAnnotation.colName());
System.out.println("nameAnnotation.type() = " + nameAnnotation.type());
System.out.println("nameAnnotation.length() = " + nameAnnotation.length());

// 获取类的Method
Method setPassword = c.getDeclaredMethod("setPassword", String.class);
// 获取Method上的注解
setPassword.getAnnotations();
}
}

获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class ReflectGet {
public static void main(String[] args) throws NoSuchMethodException {
Class c = Person.class;

// 获得类名
System.out.println("c.getName() = " + c.getName());
System.out.println("c.getSimpleName() = " + c.getSimpleName());

// 获得类的属性
Field[] fields = c.getFields(); // public属性
for (Field field : fields) {
System.out.println("field = " + field);
}
fields = c.getDeclaredFields(); // 所有属性
for (Field field : fields) {
System.out.println("declaredField = " + field);
}

// 获得类的方法
Method[] methods = c.getMethods(); // 本类及父类全部的public方法
for (Method method : methods) {
System.out.println("method = " + method);
}
methods = c.getDeclaredMethods(); // 本类的所有方法
for (Method method : methods) {
System.out.println("method = " + method);
}
Method method = c.getMethod("setAge", int.class); // 需要指定形参的类型,因为可能会重载!!!
System.out.println("method = " + method);

// 获得构造器
Constructor[] constructors = c.getConstructors(); // 获得public方法
for (Constructor constructor : constructors) {
System.out.println("constructor = " + constructor);
}
constructors = c.getDeclaredConstructors(); // 获得本类全部
for (Constructor constructor : constructors) {
System.out.println("constructor = " + constructor);
}
Constructor constructor = c.getConstructor(String.class, int.class); // 获取指定构造器,同样需要传形参的class类,可能会重载!!!
System.out.println("constructor = " + constructor);
}
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ReflectUse {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 拿到类的Class对象
Class c = Person.class;

// 获取构造器(在Java9后使用Class对象直接创建实例的方法已经被抛弃了)
Constructor constructorA = c.getDeclaredConstructor(null);
Constructor constructorB = c.getDeclaredConstructor(String.class, int.class);

// 通过构造器创建实例
Person person = (Person) constructorA.newInstance(null);
System.out.println("person = " + person);
Person personB = (Person) constructorB.newInstance("Edlison", 18);
System.out.println("personB = " + personB);

// 通过Class对象获取其中的方法
Method setName = c.getMethod("setName", String.class);

// 执行该方法: 执行的对象 形参
setName.invoke(personB, "edlison");
System.out.println("personB = " + personB);

// 通过Class对象获取其中的属性
Field age = c.getDeclaredField("age");
age.setAccessible(true); // 由于private限制 需要先设置Accessible才可以对其进行操作
age.set(personB, 10);
System.out.println("personB = " + personB);
}
}

注意

  • 通过invoke执行获得的类的方法:(需要执行的对象,形参…)
  • 通过set对类的属性进行赋值:(需要赋值的对象,形参)
  • 如果属性或方法的可见性为private,可以通过设置setAccessible(true)来访问。

介绍

Java是静态语言。

反射机制的引入,使Java能在执行期借助反射API获取任何类的内部信息,并能直接操作任何类的内部属性及方法。

正常方法:

引入’包类’名称 -> new实例化 -> 获得实例化对象

反射方法:

实例化对象 -> getClass()方法 -> 得到’包类’名称

优点:实现动态创建对象和编译。

缺点:性能有影响。

获得反射对象

1
2
3
4
Class c1 = Class.forName("com.edlison.design.v1.reflection.User");
Class c2 = Class.forName("com.edlison.design.v1.reflection.User");

System.out.println(c1 == c2); // true
  • 一个类在内存中只有一个Class对象
  • 类被加载后,类的所有信息都封装在Class对象中

1. 通过对象获得

1
Class c1 = person.getClass();

2. 通过forName获得

1
Class c2=Class.forName("com.edlison.design.v1.reflection.Student");

3. 通过类.class获得

1
Class c3 = Student.class;

4. 内置类型的Type属性

1
Class c4 = Integer.TYPE;

5. 通过子类获取父类

1
Class c5 = Student.class.getSuperclass();

类的初始化

过程

加载 -> 链接 -> 初始化

  • 类的主动引用(一定会发生类的初始化)
  • 类的被动引用(不会发生类的初始化)

结合JVM进行理解。

类加载器

类加载器是用来把类(Class)装载进内存的,JVM自顶向下定义了如下加载器。

  • 引导类加载器:C++编写,负责Java核心库,类加载器获取不到
  • 扩展类加载器:负责jre/lib/ext下的Jar包的导入。
  • 系统类加载器:负责java --classpath所指目录下类与Jar包的导入。

系统类加载器 -父类> 扩展类加载器 -父类> 引导类加载器

可以依次根据ClassLoader.getParent()取得其父类。

注意

  • 只有类加载器加载的路径下的Jar包才可以使用。
  • 双亲委派机制。

元注解

Java内置了几个元注解

  • @Target定义了作用域,可以使用的范围。
  • @Retention定义了注解的生命周期
  • @Document定义注解将被包含在JavaDoc中。
  • @Inherited说明子类可以继承父类的注解。

自定义注解

注解内可以规定要传哪些值。

1
2
3
4
5
6
7
8
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnoPlus {
String value();
String name() default "edlison";
int id() default -1;
int age();
}
  • value对应的可以不用写value = "", 可以直接传值。
  • default默认则可以不传值。
  • 传值的顺序没有要求。

用处

注解可以添加在package, class, method, field上,相当于给他们添加了额外的信息,我们可以通过反射机制编程来实现对这些元数据的访问。

静态代理模式

![image-20210202095609829](/Users/edlison/Library/Application Support/typora-user-images/image-20210202095609829.png)

架构分析

  • 抽象角色:用于设计被代理角色的方法。一般使用抽象类或接口。
  • 真实角色:被代理的角色。
  • 代理角色:对真实角色进行代理,一般还会有一些代理角色附加的业务。
  • 客户:访问代理。

好处

  • 真实角色只需要专注他需要处理的业务,更加纯粹。
  • 公共业务交给代理,实现了业务分工
  • 业务扩展方便,方便集中管理

缺点

  • 一个真实角色就会产生一个代理角色。代码量翻倍。

问题

代理模式使用组合(作为数据成员)的方式,将Host传入Proxy

如果使用继承(extends)的方式,灵活度降低。