杂杂碎知识

最近在阅读 spring 源码,学到很多原来没用过的 java api,如果未来自己要实现某些框架,将非常有用。

注解方面

所有的注解都继承自 Annotation 接口


@Inherited
一般而言子类上是看不到父类上的注解的,除非这个注解上加了 @Inherited 注解


@Retention(RetentionPolicy.RUNTIME)
用来修饰注解保留的时间,有三个值,默认值为 CLASS

  • SOURCE 只保留在源代码阶段,不会被编译,用于一些做检查的操作,如@SuppressWarnings、@Override
  • CLASS 只保留在class文件中,可以通过编译,但不会被jvm执行
  • RUNTIME 可以被jvm执行,比如需要运行时获取注解信息,如反射

AnnotatedElement 接口

表示当前在此虚拟机中运行的程序的带批注元素。此接口允许反射地读取批注。全部
此接口中的方法返回的批注是不可变和可序列化的。此接口的方法返回的数组可以由调用方修改,而不影响返回给其他调用方的数组。

这个接口中有一些方法很实用,如果获取不到某些注解,确保注解上有@Retention(RetentionPolicy.RUNTIME)

  • getAnnotations() 获取此类上的所有注解
  • getDeclaredAnnotations() 获取此类上的所有注解(不包括此类父类上的注解)
  • isAnnotationPresent() 判断此类上是否有某个注解(包括父类上的注解)

这个接口有很多实现,例如 Package、Class、Method、Field

Class 方面

在Class.java中的注释提到,类分为五种:

1
2
3
4
5
6
// There are five kinds of classes (or interfaces):
// a) Top level classes
// b) Nested classes (static member classes)
// c) Inner classes (non-static member classes)
// d) Local classes (named classes declared within a method)
// e) Anonymous classes
  • a:顶级类
  • b:静态内部类
  • c:非静态内部类
  • d:在方法内定义的类
  • e:匿名类

spring中 ClassMetadata 接口中的 boolean isIndependent();方法,根据其注释描述,功能为 确定类是否独立,即是否是顶级类(top level)或嵌套类(静态内部类)可以独立于封闭类构造。
查看SimpleAnnotationMetadata的实现

1
2
3
public boolean isIndependent() {
return (this.enclosingClassName == null || this.independentInnerClass);
}

先判断enclosingClassName是否为null,即是否是top level 类,如果不是,再判断independentInnerClass,即是否是静态内部类。
如何获取 enclosingClassName 变量的呢? Class中有方法 Class<?> getEnclosingClass(),如果一个类不是top level的话,就会返回包含这个类的 top level,如果类是top level,那么返回 null 。
如何获取 independentInnerClass 变量的呢?spring使用了ASM技术:

ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

简单说ASM能够解析class文件内容,且提供接口能CRUD,而反射只能读取内容。

再看一下independentInnerClass变量是什么时候被赋值的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void visitInnerClass(String name, @Nullable String outerName, String innerName,
int access) {
if (outerName != null) {
String className = toClassName(name);
String outerClassName = toClassName(outerName);
if (this.className.equals(className)) {
this.enclosingClassName = outerClassName;
// 如果是access的并且有 static 字段。并且这个方法是访问内部类的时候才会调用,即还要是内部类(方法名表意)
this.independentInnerClass = ((access & Opcodes.ACC_STATIC) != 0);
}
else if (this.className.equals(outerClassName)) {
this.memberClassNames.add(className);
}
}
}

spring

Aware接口是什么,有什么用处?

设计模式

可以使用枚举来实现工厂模式,更加优雅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface FoodFactory {
Food makeFood();
}
public enum ChineseFoodFactory implements FoodFactory {
A() {
@Override
public Food makeFood() {
return new ChineseFoodA();
}
},
B() {
@Override
public Food makeFood() {
return new ChineseFoodB();
}
}
}
Food foodA = ChineseFoodFactory.valueOf("A").makeFood();

Food foodB = ChineseFoodFactory.B.makeFood();