目 录
一、反射 Class 的 Method
1.反编译 String 类的方法签名
2.通过反射调用方法
3.反编译 String 类的构造方法签名
4.通过反射调用构造方法
二、类加载过程
1.装载(Loading)
(1)说明
(2)双亲委派机制
2.链接(Linking)
(1)验证(Verify)
(2)准备(Prepare)
(3)解析(Resolve)
3.初始化(initialization)
三、类加载器获取 Class
1.说明
2.与 Class.forName() 比较
四、反射的泛型
1.父类的泛型
2.接口的泛型
3.属性的泛型
4.方法参数的泛型
5.方法返回值的泛型
6.构造方法参数的泛型
一、反射 Class 的 Method
1.反编译 String 类的方法签名
public class MethodTest {public static void main(String[] args) throws ClassNotFoundException {// 获取类信息Class<?> aClass = Class.forName("java.lang.String");// 获取类修饰符String classMod = Modifier.toString(aClass.getModifiers());// 获取简单类名String className = aClass.getSimpleName();// 获取简单父类名String classSupName = aClass.getSuperclass().getSimpleName();// 获取父类接口Class<?>[] classInterfaces = aClass.getInterfaces();// 获取所有方法Method[] declaredMethods = aClass.getDeclaredMethods();// 字符串拼接StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(classMod);stringBuilder.append(" class ");stringBuilder.append(className);stringBuilder.append(" extends ");stringBuilder.append(classSupName);if (classInterfaces.length > 0) {stringBuilder.append(" implements ");for (int i = 0; i < classInterfaces.length; i++) {stringBuilder.append(classInterfaces[i].getSimpleName());if (i != classInterfaces.length - 1) {stringBuilder.append(", ");}}}stringBuilder.append(" {\n");for (Method declaredMethod : declaredMethods) {stringBuilder.append("\t");// 获取方法修饰符String methodMod = Modifier.toString(declaredMethod.getModifiers());stringBuilder.append(methodMod);stringBuilder.append(" ");// 获取方法返回值类型Class<?> returnType = declaredMethod.getReturnType();stringBuilder.append(returnType.getSimpleName());stringBuilder.append(" ");// 获取方法名String methodName = declaredMethod.getName();stringBuilder.append(methodName);// 获取方法参数类型stringBuilder.append(" (");Parameter[] parameters = declaredMethod.getParameters();for (int i = 0; i < parameters.length; i++) {Parameter parameter = parameters[i];// 获取参数类型Class<?> parType = parameter.getType();stringBuilder.append(parType.getSimpleName());// 获取参数名String parName = parameter.getName();stringBuilder.append(" ");stringBuilder.append(parName);// 添加逗号分隔符,最后一个参数不加逗号if (i < parameters.length - 1) {stringBuilder.append(", ");}}stringBuilder.append(") {}\n");}stringBuilder.append("}");System.out.println(stringBuilder);}
}
2.通过反射调用方法
- 四要素:对象、方法、参数、值。缺一不可;
- 若方法不是 public 的,运行会报【java.lang.IllegalAccessException】异常,需要通过 setAccessible(true) 打破封装;
public class Person {public String name;private int age;protected String sex;public static String country;public static final String job = "程序员";public Person() {}public Person(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public static String getCountry() {return country;}public static void setCountry(String country) {Person.country = country;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}private void test(String s) {System.out.println("test(" + s + ")方法执行完毕!");}
}
public class UseMethod {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {Person person = new Person();Class<? extends Person> aClass = person.getClass();// 获取方法Method test = aClass.getDeclaredMethod("test", String.class);// 设置方法可访问test.setAccessible(true);// 调用方法Object o = test.invoke(person, "参数列表");}
}
3.反编译 String 类的构造方法签名
public class MethodTest2 {public static void main(String[] args) throws ClassNotFoundException {// 获取类Class<?> aClass = Class.forName("java.lang.String");// 获取类修饰符String classMod = Modifier.toString(aClass.getModifiers());// 获取简单类名String className = aClass.getSimpleName();// 获取简单父类名String classSupName = aClass.getSuperclass().getSimpleName();// 获取父类接口Class<?>[] classInterfaces = aClass.getInterfaces();// 获取构造方法Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();// 拼接字符串StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(classMod);stringBuilder.append(" class ");stringBuilder.append(className);stringBuilder.append(" extends ");stringBuilder.append(classSupName);if (classInterfaces.length > 0) {stringBuilder.append(" implements ");for (int i = 0; i < classInterfaces.length; i++) {stringBuilder.append(classInterfaces[i].getSimpleName());if (i != classInterfaces.length - 1) {stringBuilder.append(", ");}}}stringBuilder.append(" {\n");for (Constructor<?> declaredConstructor : declaredConstructors) {// 获取构造方法修饰符String constructorMod = Modifier.toString(declaredConstructor.getModifiers());stringBuilder.append("\t");stringBuilder.append(constructorMod);// 获取构造方法名String constructorName = declaredConstructor.getName().replaceAll("java.lang.", "");stringBuilder.append(" ");stringBuilder.append(constructorName);// 获取构造方法参数Parameter[] parameters = declaredConstructor.getParameters();stringBuilder.append(" (");if (parameters.length > 0) {for (int i = 0; i < parameters.length; i++) {// 获取参数类型String paraType = parameters[i].getType().getSimpleName();stringBuilder.append(paraType);// 获取参数名String paraName = parameters[i].getName();stringBuilder.append(" ");stringBuilder.append(paraName);if (i != parameters.length - 1) {stringBuilder.append(", ");}}}stringBuilder.append(") {}\n");}stringBuilder.append("}");System.out.println(stringBuilder);}
}
4.通过反射调用构造方法
public class Person {public String name;private int age;protected String sex;public static String country;public static final String job = "程序员";public Person() {}public Person(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public static String getCountry() {return country;}public static void setCountry(String country) {Person.country = country;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}
}
public class UseConstructor {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Person person = new Person();// 获取Class对象Class<? extends Person> aClass = person.getClass();// 获取无参构造方法Constructor<? extends Person> c1 = aClass.getDeclaredConstructor();System.out.println(c1);Person p1 = c1.newInstance();System.out.println(p1);// 获取有参构造方法Constructor<? extends Person> c2 = aClass.getDeclaredConstructor(String.class, int.class, String.class);System.out.println(c2);Person p2 = c2.newInstance("孔明", 18, "男");System.out.println(p2);}
}
二、类加载过程
1.装载(Loading)
(1)说明
- 类加载器负责将类的 class 文件读入内存;
- 低版本 JDK 类加载器:
- 引导 / 启动 类加载器:负责加载 rt.jar,即核心类库;
- 扩展 类加载器:负责加载 ext/*.jar ;
- 系统 类加载器:负责加载 classpath 中的 class 文件。
- jdk 9 之后的 JDK 类加载器:
- BootstrapClassLoader(引导 / 启动 类加载器);
- PlatformClassLoader(平台类加载器);
- AppClassLoader(应用类加载器)。
- 高版本 JDK 中引入模块化;
- 可以自定义类加载器,只要符合规范即可;
- 可以通过 getParent() 方法获取 当前 类加载器 的 父 类加载器。
public class ClassLoaderTest {public static void main(String[] args) {// 获取应用类加载器ClassLoader cl1 = Person.class.getClassLoader();System.out.println(cl1);ClassLoader cl2 = ClassLoader.getSystemClassLoader();System.out.println(cl2);ClassLoader cl3 = Thread.currentThread().getContextClassLoader();System.out.println(cl3);// 获取平台类加载器ClassLoader cl1Parent = cl1.getParent();System.out.println(cl1Parent);ClassLoader cl2Parent = cl2.getParent();System.out.println(cl2Parent);ClassLoader cl3Parent = cl3.getParent();System.out.println(cl3Parent);// 获取启动类加载器,启动类加载器负责加载核心类库,名称读不到,直接输出 nullClassLoader cl1GrandParent = cl1Parent.getParent();System.out.println(cl1GrandParent);ClassLoader cl2GrandParent = cl2Parent.getParent();System.out.println(cl2GrandParent);ClassLoader cl3GrandParent = cl3Parent.getParent();System.out.println(cl3GrandParent);}
}
(2)双亲委派机制
- 某个类加载器接收到加载类的任务时,通常委托给【父 类加载器】完成加载;
- 顶级【父 类加载器】无法加载时,逐层向下委派加载任务;
- 这样做的原因是,可以保证程序的安全,也可以防止类加载重复。
2.链接(Linking)
(1)验证(Verify)
确保类加载信息符合 JVM 规范。
(2)准备(Prepare)
- 正式为静态变量在方法区开辟存储空间并赋默认值;
- 举例如下:
- public static int i = 1; // 实际上,赋默认值 0
- public static final int i = 1; // 此时赋值 1
(3)解析(Resolve)
将虚拟机常量池中的符号引用替换为直接引用,即替换为地址。
3.初始化(initialization)
- 为静态变量赋值;
- 执行静态代码块。
三、类加载器获取 Class
1.说明
上一节谈到,通过类加载器的方式可以获取 Class 。下面将做出详细解释:
public class ReflectLoader {public static void main(String[] args) throws ClassNotFoundException {// 获取 系统类 / 应用类 加载器,负责加载 classpath 中的 class 文件ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println(systemClassLoader);// 加载 class,只是完成了类加载过程中的装载与链接,还没有初始化Class<?> aClass = systemClassLoader.loadClass("reflecttest.Person");System.out.println(aClass);// 在这个类第一次被真正使用的时候,才会初始化这个类}
}
public class Person {public String name;private int age;protected String sex;public static String country;public static final String job = "程序员";static {System.out.println("Person类静态代码块执行了");}public Person() {}public Person(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public static String getCountry() {return country;}public static void setCountry(String country) {Person.country = country;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}
}
2.与 Class.forName() 比较
Class.forName() 会完成类加载的全部过程,如果使用类加载器的方式,可以看出没有执行静态代码块,也就是没有执行初始化的过程。而使用 Class.forName() 的方式,可以看到静态代码块执行了。
public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException {Class<?> aClass = Class.forName("reflecttest.Person");System.out.println(aClass);}
}
四、反射的泛型
1.父类的泛型
public class Animal<A, B, C> {
}
public class Dog extends Animal<String, Integer, Boolean> {
}
public class Test {public static void main(String[] args) {// 反射获取类Class<Dog> dogClass = Dog.class;// 获取当前类的父类泛型Type genericSuperclass = dogClass.getGenericSuperclass();// 如果父类使用了泛型if (genericSuperclass instanceof ParameterizedType){// 转换为参数化类型ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;// 获取泛型数组Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();// 遍历泛型数组for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument.getTypeName());}}}
2.接口的泛型
public interface Animal<T, V, K> {
}
public class Cat implements Animal<String, Integer, Boolean> {
}
public class Test {public static void main(String[] args) {// 反射获取类Class<Cat> catClass = Cat.class;// 获取接口的泛型Type[] genericInterfaces = catClass.getGenericInterfaces();for (Type genericInterface : genericInterfaces) {if (genericInterface instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericInterface;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}}
}
3.属性的泛型
public class Animal {public Map<Integer, Boolean> name;
}
public class Test {public static void main(String[] args) throws NoSuchFieldException {// 反射获取类Class<Animal> animalClass = Animal.class;// 获取属性Field field = animalClass.getField("name");// 获取属性泛型Type genericType = field.getGenericType();if (genericType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}
}
4.方法参数的泛型
public class Animal {public void eat(List<String> food) {}
}
public class Test {public static void main(String[] args) throws NoSuchMethodException {// 反射获取类Class<Animal> animalClass = Animal.class;// 获取方法Method declaredMethod = animalClass.getDeclaredMethod("eat", List.class);// 获取方法参数泛型Type[] genericParameterTypes = declaredMethod.getGenericParameterTypes();for (Type genericParameterType : genericParameterTypes) {if (genericParameterType instanceof ParameterizedType){ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}}
}
5.方法返回值的泛型
public class Animal {public Map<String, Integer> eat(List<String> food) {return null;}
}
public class Test {public static void main(String[] args) throws NoSuchMethodException {// 反射获取类Class<Animal> animalClass = Animal.class;// 获取方法Method declaredMethod = animalClass.getDeclaredMethod("eat", List.class);// 获取方法返回值的泛型Type genericReturnType = declaredMethod.getGenericReturnType();if (genericReturnType instanceof ParameterizedType){ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}
}
6.构造方法参数的泛型
public class Animal {private Map<String, Boolean> name;public Animal(Map<String, Boolean> name) {this.name = name;}
}
public class Test {public static void main(String[] args) throws NoSuchMethodException {// 反射获取类Class<Animal> animalClass = Animal.class;// 获取构造方法Constructor<Animal> animal = animalClass.getDeclaredConstructor(Map.class);// 获取构造方法参数泛型Type[] genericParameterTypes = animal.getGenericParameterTypes();for (Type genericParameterType : genericParameterTypes) {if (genericParameterType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}}
}