嘿嘿,接下来一步步拆解吧!!!
1.在标准 Java 编译过程中(通过javac编译器编译.java文件),所有类都会生成对应的.class文件
那么要是当前程序没有用到某个类,那个类也会生成对应的.class文件吗?
- 答案是:会!
原因是:.class文件的生成是编译阶段的行为(由javac编译器完成),而 “是否会被调用执行” 是运行阶段的行为—— 两者完全独立,编译时不会判断类是否被使用,只要源文件中定义了类,就会生成对应的.class文件。javac的职责是将.java源文件中所有类定义(无论是否被使用)转换为字节码,并生成对应的.class文件,它不分析类在运行时是否被调用、是否有用,仅负责语法校验和字节码生成。
2.ClassLoader的核心作用
-
①定位字节码:从磁盘(如classes目录)、网络(如 Applet)、内存(动态生成的字节码)等位置找到类的字节码(.class文件)
-
②读取字节码:将字节码数据读取到 JVM 内存中
-
③生成 Class 对象:将字节码解析为 JVM 可识别的格式,在方法区(Method Area)生成对应的Class对象(类的元数据),作为后续创建实例的 “模板”
3.真正开始的Class对象(前面都是做好铺垫)
-
①创建实例对象时,若类未加载,JVM 会自动加载类并创建对应的Class对象;若类已加载,则直接使用已有的Class对象
-
②获取Class对象
- 类名.class:编译时就能确定要获取的类,效率高
- 对象.getClass():需要先有实例对象
- Class.forName(全类名):参数为全限定名(动态加载)
-
③通过Class对象实例化对象
- a.获取无参构造器(参数列表为空)
Constructor<?> noArgConstructor = userClass.getConstructor(); User user = (User)noArgConstructor.newInstance();- b.获取单参构造器(参数类型为String.class)
Constructor<?> singleArgConstructor = userClass.getConstructor(String.class); User user = (User)singleArgConstructor.newInstance("张三");- c. 获取私有多参构造器(参数类型为String.class, int.class)
Constructor<?> privateConstructor = userClass.getDeclaredConstructor(String.class, int.class); privateConstructor.setAccessible(true); // 设置私有构造器可访问(关闭访问检查),只要访问私有或其他不可访问的都需要 User user = (User)privateConstructor.newInstance("李四", 20);
4.反射调用私有方法
- 4.1 调用私有非静态方法,必须持有实例,说明是调用该实例中的方法。
