类型信息

类型信息

运行时类型信息,能够在程序运行时发现和使用类型信息。


Class对象

Class对象用来表示运行时的类型信息。

类是程序的一部分, 每个类都有一个Class对象。 被保存在一个同名的.class文件中。 为了生产这个类的对象, JVM会先调用“类加载器”子系统来把这个类加载到内存中。

类加载器子系统可能包含一条类加载器链, 但是有且只有一个原生类加载器。
它是JVM实现的一部分,通常在这条链中,不需要添加额外的类加载器,但是如果有特殊需要, (比如以某种特殊的方式加载类,以支持web服务器应用,或者网络下载类。可以以挂载其他额外的类加载器。)

当程序创建一个类的静态成员时, 就会加载这个类。 (构造函数就是静态的,只是省略了static)

类加载器首先会检查这个类的Class对象有没有加载,如果没有, 就会根据类名加载.class文件。 JVM会对加载后的字节码进行验证,确保没有损坏

反射

Java不允许在运行时改变程序结构或类型变量的结构, 但是它允许在运行时探知、加载、调用在编译期完全未知的class, 可以在运行时加载class, 生成实例对象, 嗲用method , 或者field赋值。

这种类似于看透了class的特性称为反射。在java.lang.reflect库中包含类Field、Method和Constructor。对应了成员变量, 方法, 和构造方法

动态代理

代理是基本的设计模式之一。 一个对象封装真实的对象, 代替其提供其他或者不同的操作, 这些操作通常涉及与真实对象的通信, 代理对象通常作为中间对象。

Java的动态代理, 不仅动态创建代理对象, 而且动态处理对代理方法的调用。 在动态代理上进行的所有调用都被重定向到单个调用处理程序, 该处理程序负责发现调用内容并决定如何处理。

JDK动态代理

使用JDK动态代理的基本步骤

  1. 通过实现InvocationHandler接口来定义一个自己的调用处理器
  2. 通过Proxy.newProxyInstance获得代理对象
  3. 通过代理对象调用目标方法
JDK动态代理源码分析
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
44
45
46
47
48
49
50
51
52
53
54
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 判断调用处理器是否为空
Objects.requireNonNull(h);
// 拷贝代理类实现的接口, 用于权限的检查
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// 对安全权限进行检查
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}

/*
* 查找和生成代理类
*/
Class<?> cl = getProxyClass0(loader, intfs);

/*
* 使用指定的程序处理器获取构造函数对象
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}

final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
// 如果构造器是private的, 就使用反射来setAccessible
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 根据代理类的构造起生成代理对象并返回
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}

代理类的生成方法getProxyClass0(loader, intfs);

1
2
3
4
5
6
7
8
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 如果缓存中包含接口数组和类加载器已存在,则返回缓存副本,否则通过ProxyClassFactory创建一个对应的class对象
return proxyClassCache.get(loader, interfaces);
}
1
2
3
4
5
6
7
8
9
10
11
12
public V get(K key, P parameter) {
...
...
...
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
// apply()方法调用ProxyClassFactory的apply方法
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
...
...
...
}

ProxyClassFactory的apply()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
...
...
...
/*
* 生成指定的代理类
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
...
...
...
}

进入generateProxyClass()又调用了proxyGenerator.generateClassFile();

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
private byte[] generateClassFile() {
// 将object类中的hashcode,equals,toString方法添加到动态代理类中
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
Class[] var1 = this.interfaces;
int var2 = var1.length;

int var3;
Class var4;
// 遍历父接口数据
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
// 获取每个接口当中的方法
Method[] var5 = var4.getMethods();
int var6 = var5.length;

//遍历接口中的方法, 将接口中的方法都添加到动态代理类中
for(int var7 = 0; var7 < var6; ++var7) {
Method var8 = var5[var7];
this.addProxyMethod(var8, var4);
}
}

Iterator var11 = this.proxyMethods.values().iterator();

//检查代理类的返回类型
List var12;
while(var11.hasNext()) {
var12 = (List)var11.next();
checkReturnTypes(var12);
}

Iterator var15;
try {
// 将构造方法添加到代理类中
this.methods.add(this.generateConstructor());
var11 = this.proxyMethods.values().iterator();

// 遍历代理类中的方法,使用两层循环, 因为方法会被重载, 同名的方法可能有多种
while(var11.hasNext()) {
var12 = (List)var11.next();
var15 = var12.iterator();

while(var15.hasNext()) {
ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
this.methods.add(var16.generateMethod());
}
}
// 将静态代码块添加到代理类
this.methods.add(this.generateStaticInitializer());
} catch (IOException var10) {
throw new InternalError("unexpected I/O Exception", var10);
}
...
...
...
}

Optional类

当操作的对象是null时, 会产生NullPointException异常。
Optional对象可以防止代码抛出空指针的异常