1、类的加载过程

当程序主动的使用了某个类,该类还未被加载到内存中,则系统会通过上面的三个步骤对类进行初始化:

  • 类的加载: 将类的class文件读入内存,并为之创建一个java.lang.Class对象
  • 类的链接:将类的二进制数据合并到JRE中
  • 类的初始化:JVM负责对类进行初始化

2、什么时候发生类的初始化

2.1、类的主动引用(一定会发生类的初始化)

  • 当虚拟机启动,先初始化main方法所在的类
  • new一个类的对象
  • 调用类的静态成员(除了final常量)和静态方法
  • 使用java.lang.reflect包的方法对类进行反射调用
  • 当初始化一个类,如果父类没有被初始化,则会先去初始化它的父类

2.1、类的被动引用(不会发生类的初始化)

  • 当访问一个静态域时,只要真正声明这个域的类才会被初始化。如通过子类引用父类的静态变量,不会导致子类的初始化
  • 通过数组定义类的引用,不会触发此类的初始化
  • 引用常量

3、获取类运行时的结构

获得类的信息

  1. package reflection;
  2. import java.lang.reflect.Field;
  3. public class Demo3 {
  4. public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
  5. Class c1 = Class.forName("reflection.User3");
  6. // 获取类名
  7. System.out.println(c1.getName()); // 包名 + 类名
  8. System.out.println(c1.getSimpleName());
  9. // 获取属性
  10. Field[] fields = c1.getDeclaredFields();
  11. for (Field field : fields) {
  12. System.out.println(field);
  13. }
  14. // 获得指定属性的值
  15. Field name = c1.getDeclaredField("name");
  16. System.out.println(name);
  17. }
  18. }
  19. // 实体类
  20. class User3 {
  21. private String name;
  22. private int id;
  23. private int age;
  24. // 无参构造
  25. public User3() {
  26. }
  27. public User3(String name, int id, int age) {
  28. this.name = name;
  29. this.id = id;
  30. this.age = age;
  31. }
  32. @Override
  33. public String toString() {
  34. return "User{" +
  35. "name='" + name + '\'' +
  36. ", id=" + id +
  37. ", age=" + age +
  38. '}';
  39. }
  40. }

4、动态创建对象的执行方法

创建类的对象:调用Class对象的newInstance()方法

  • 类必须有一个无参构造器
  • 类的构造器的访问权限需要足够

调用指定的方法:通过反射,调用类中方法,通过Method类完成

  1. import java.lang.reflect.Constructor;
  2. import java.lang.reflect.InvocationTargetException;
  3. import java.lang.reflect.Method;
  4. public class Demo4 {
  5. public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
  6. // 获得Class对象
  7. Class c1 = Class.forName("reflection.User");
  8. // 构造一个对象(无参数构造)
  9. User user = (User) c1.newInstance();
  10. System.out.println(user);
  11. // 通过构造器创建对象
  12. Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
  13. User user2 = (User) constructor.newInstance("demo", 1, 11);
  14. System.out.println(user2);
  15. // 通过反射调用普通方法
  16. User user3 = (User) c1.newInstance();
  17. Method setName = c1.getDeclaredMethod("setName", String.class);
  18. setName.invoke(user3, "joinmouse");
  19. System.out.println(user3.getName());
  20. }
  21. }

5、获取泛型信息

Java采用泛型擦除机制来引入泛型,Java中的泛型仅仅是给编译器的javac使用,确保数据的安全性和免去强制类型转换问题,但是一旦编译完成,所有泛型和有关的类型都会被擦除

为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType、TypeVaribale、WildcardType几种类型来代表能不能归一到Class类中的类型但有何原始类型齐名的类型

  1. public class Demo5 {
  2. public void test01(Map<String, User> map, List<User> list) {
  3. System.out.println("test01");
  4. }
  5. public static void main(String[] args) throws NoSuchMethodException {
  6. Method method = Demo5.class.getMethod("test01", Map.class, List.class);
  7. // 获取泛型
  8. Type[] genericParameterTypes = method.getGenericParameterTypes();
  9. for(Type genericParameterType : genericParameterTypes) {
  10. System.out.println(genericParameterType);
  11. // 判断类型属于参数化类型
  12. if(genericParameterType instanceof ParameterizedType) {
  13. Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
  14. for (Type actualTypeArgument : actualTypeArguments) {
  15. System.out.println(actualTypeArgument);
  16. }
  17. }
  18. }
  19. }
  20. }
  21. // 打印信息
  22. java.util.Map<java.lang.String, reflection.User>
  23. class java.lang.String
  24. class reflection.User
  25. java.util.List<reflection.User>
  26. class reflection.User

6、获取注解信息

反射操作注解:getAnnotations

ORM:Object relationship Mapping 对象关系映射

利用反射和注解完成类和表结构的映射关系

  1. import java.lang.annotation.*;
  2. import java.lang.reflect.Field;
  3. public class Demo6 {
  4. public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
  5. Class c1 = Class.forName("reflection.Student2");
  6. // 通过反射获得注解
  7. Annotation[] annotations = c1.getAnnotations();
  8. for (Annotation annotation : annotations) {
  9. System.out.println(annotation);
  10. }
  11. // 获得注解value的值
  12. Table table = (Table) c1.getAnnotation(Table.class);
  13. String value = table.value();
  14. System.out.println(value);
  15. // 获得类指定的注解
  16. Field field = c1.getDeclaredField("id");
  17. FieldDb annotation = field.getAnnotation(FieldDb.class);
  18. System.out.println(annotation.columnName());
  19. System.out.println(annotation.type());
  20. System.out.println(annotation.length());
  21. }
  22. }
  23. @Table("db_student")
  24. class Student2 {
  25. @FieldDb(columnName = "db_id", type="int", length = 10)
  26. private int id;
  27. @FieldDb(columnName = "db_age", type="int", length = 10)
  28. private int age;
  29. @FieldDb(columnName = "db_name", type="varchar", length = 30)
  30. private String name;
  31. public Student2() {
  32. }
  33. public void Student2(int id, int age, String name) {
  34. this.id = id;
  35. this.age = age;
  36. this.name = name;
  37. }
  38. public int getId() {
  39. return id;
  40. }
  41. public void setId(int id) {
  42. this.id = id;
  43. }
  44. public int getAge() {
  45. return age;
  46. }
  47. public void setAge(int age) {
  48. this.age = age;
  49. }
  50. public String getName() {
  51. return name;
  52. }
  53. public void setName(String name) {
  54. this.name = name;
  55. }
  56. @Override
  57. public String toString() {
  58. return "Student2{" +
  59. "id=" + id +
  60. ", age=" + age +
  61. ", name='" + name + '\'' +
  62. '}';
  63. }
  64. }
  65. // 类名的注解
  66. @Target(ElementType.TYPE)
  67. @Retention(RetentionPolicy.RUNTIME)
  68. @interface Table {
  69. String value();
  70. }
  71. // 属性的注解
  72. @Target(ElementType.FIELD)
  73. @Retention(RetentionPolicy.RUNTIME)
  74. @interface FieldDb {
  75. String columnName();
  76. String type();
  77. int length();
  78. }