题记:
记录一下java反射中的一些面试问题
区别:
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
第二个参数是true,表示是否初始化,默认是初始化,一旦初始化,就会出发对象的静态代码块和静态参数的初始化,请看类的装在过程
加载:通过累的全限定名获取二进制字节流,将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lang.class对象;
链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;
校验:检查导入类或接口的二进制数据的正确性;(文件格式验证,元数据验证,字节码验证,符号引用验证)
准备:给类的静态变量分配并初始化存储空间;
解析:将常量池中的符号引用转成直接引用;
初始化:激活类的静态变量的初始化Java代码和静态Java代码块,并初始化程序员设置的变量值。
代码示例:
@Data
@Builder
public class Product implements Serializable {
private static String staticMethod = staticMethod();
static {
System.out.println("静态代码块执行");
}
private String name;
private String address;
private static String staticMethod(){
System.out.println("静态方法执行");
return "静态方法块执行";
}
}
执行实例:
public class Demo2 {
@Test
public void test1() throws ClassNotFoundException {
System.out.println("class.forName 执行================");
Class.forName("com.edward.sg.owner.server.Product");
System.out.println("classLoader 执行=================");
ClassLoader.getSystemClassLoader().loadClass("com.edward.sg.owner.server.Product");
}
}
执行结果
class.forName 执行================
静态方法执行
静态代码块执行
classLoader 执行=================
classLoader执行结果可以看出没有进行类的初始化,只是将类加载到虚拟机中,class.forName进行类的初始化
jdbc中使用了class.forname进行类的初始化,加载静态方法
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
/**
* Construct a new driver and register it with DriverManager
*
* @throws SQLException
* if a database error occurs.
*/
public Driver() throws SQLException {
// Required for Class.forName().newInstance()
}
}
DriverManager.registerDriver(new Driver())和 Class.forName(),其中DriverManager.registerDriver会导致实例化了两次Driver与Driver初始化的时候运行静态代码块相关
Spring IoC 的 Lazy loading 有关, Spring IoC 为了加快初始化速度, 因此大量使用了延时加载技术. 而使用 classloader 不需要执行类中的初始化代码, 可以加快加载速度, 把类的初始化工作留到实际使用到这个类的时候(感兴趣的同学还可以看看 IOC中的循环依赖的问题 https://www.jianshu.com/p/f0c005c7354b)
欢迎关注作者公众号交流以及投稿
回复 8888可以领取面试资料
ref: