文章目录
什么是反射
- Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期
借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内
部属性及方法 - 反射可以调用类的私有结构:私有的构造器、属性和方法。
Class类
- Class类是反射的源头
- 类的加载过程
程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。
使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件
加载到内存中。此过程就称为类的加载。
- 加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。
获取Class对象的方式
- 调用运行时类的属性:.class
//方式一:调用运行时类的属性:.class
Class<Movie> clazz = Movie.class;
System.out.println(clazz);
- 通过运行时类的对象,调用getClass()
//方式二:通过运行时类的对象,调用getClass()
Movie movie = new Movie();
Class<? extends Movie> clazz1 = movie.getClass();
System.out.println(clazz1);
- 调用Class的静态方法:forName(String classPath)
//方式三:调用Class的静态方法:forName(String classPath)
try {
Class<?> clazz2 = Class.forName("com.refine.day04.java.Movie");
System.out.println(clazz2);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
- 使用类的加载器:ClassLoader
//方式四:使用类的加载器:ClassLoader
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
try {
Class<?> clazz3 = classLoader.loadClass("com.refine.day04.java.Movie");
System.out.println(clazz3);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
- 哪些类型可以有Class对象
class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
interface:接口
[]:数组
enum:枚举
annotation:注解@interface
primitive type:基本数据类型
void
类的加载
- 类的加载(Load)
将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成; - 类的链接(Link)
将类的二进制数据合并到JRE中 - 类的初始化(Initialize)
JVM负责对类对象初始化
类加载器:ClassLoader
- 类加载的作用
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。 - 类加载器分类
- 引导类加载器:负责java核心平台库,该加载器无法直接获取
- 扩展类加载器
- 系统类加载器
使用ClassLoader加载配置文件
Properties properties=new Properties();
//读取配置文件的方式二:使用ClassLoader
//配置文件默认识别为:当前module的src下
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
try {
properties.load(is);
Object name = properties.get("name");
Object password = properties.get("password");
System.out.println(name+"\t"+password);
} catch (IOException e) {
throw new RuntimeException(e);
}finally{
if( is != null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
创建运行时对象
- newInstance():此方法可以创建运行时对象
- 运行时类必须提供空参的构造器;
- 空参的构造器的访问权限修饰符需要设置为默认、protected、public,不能设置为private。通常,设置为public。
Class<Movie> clazz = Movie.class;
try {
Movie movie = clazz.newInstance();
System.out.println(movie);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
反射的动态性
- Class.forName():编译期间无法确定创建何种对象,只有在运行期间才可以确定,体现了反射的动态性。
@Test
public void test() {
int num = new Random().nextInt(3);//0,1,2
String classPath = "";
switch (num) {
case 0:
classPath = "java.util.Date";
break;
case 1:
classPath = "java.lang.Object";
break;
case 2:
classPath = "com.refine.day04.java.Movie";
break;
}
Object obj = null;
try {
obj = getInstance(classPath);
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println(obj);
}
public Object getInstance(String classPath) throws Exception{
Class clazz = Class.forName(classPath);
return clazz.newInstance();
}
获取运行时类的完整结构
获取属性结构
- getFields():获取当前运行时类及其父类中声明为public访问权限的属性
- getDeclaredFields():当前运行时类中声明的所有属性
@Test
public void test1(){
Class<Teacher> clazz = Teacher.class;
//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = clazz.getFields();
System.out.println("fields------------------");
for(Field field:fields){
System.out.println(field);
}
System.out.println("declaredFields------------------");
//当前运行时类中声明的所有属性。(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
for(Field field:declaredFields){
System.out.println(field);
}
}
- field.getModifiers():权限修饰符
- field.getType():数据类型
- field.getName():变量名
@Test
public void test2(){
Class<Teacher> clazz = Teacher.class;
Field[] declaredFields = clazz.getDeclaredFields();
for(Field field:declaredFields){
//权限修饰符
int modifiers = field.getModifiers();
System.out.print(Modifier.toString(modifiers)+" ");
//2.数据类型
Class<?> fieldType = field.getType();
System.out.print(fieldType+" ");
//3.变量名
String fieldName = field.getName();
System.out.println(fieldName);
}
}
获取方法结构
- getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
- getDeclaredMethods():获取当前运行时类中声明的所有方法
@Test
public void test1(){
Class<Teacher> clazz = Teacher.class;
//获取当前运行时类及其所有父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for(Method method:methods){
System.out.println(method);
}
//获取当前运行时类中声明的所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method:declaredMethods){
System.out.println(method);
}
}
- method.getAnnotations():获取方法声明的注解
- method.getModifiers():获取方法的权限修饰符
- method.getReturnType():返回值类型
- method.getName():方法名
@Test
public void test2(){
Class<Teacher> clazz = Teacher.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method:declaredMethods){
//1.获取方法声明的注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation:annotations){
System.out.println(annotation);
}
//2.权限修饰符
int modifiers = method.getModifiers();
System.out.println(Modifier.toString(modifiers));
//3.返回值类型
System.out.println(method.getReturnType());
//4.方法名
System.out.println(method.getName());
//5.形参列表
Class<?>[] parameterTypes = method.getParameterTypes();
if(!(parameterTypes == null && parameterTypes.length == 0)){
for(int i = 0;i < parameterTypes.length;i++){
if(i == parameterTypes.length - 1){
System.out.print(parameterTypes[i].getName() + " args_" + i);
break;
}
System.out.println(parameterTypes[i].getName()+" args_" + i + ",");
}
}
}
}
获取构造器结构
- getConstructors():获取当前运行时类中声明为public的构造器
- getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
@Test
public void test1(){
Class<Teacher> clazz = Teacher.class;
//getConstructors():获取当前运行时类中声明为public的构造器
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor constructor:constructors){
System.out.println(constructor);
}
//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor constructor:declaredConstructors){
System.out.println(constructor);
}
}
调用运行时类指定属性
- field.setAccessible(true):设置当前属性是可访问的
- field.set():指定属性值
@Test
public void test1(){
Class<Teacher> clazz = Teacher.class;
//创建运行时类的对象
try {
Teacher teacher = clazz.newInstance();
Field name = clazz.getDeclaredField("name");
//2.保证当前属性是可访问的
name.setAccessible(true);
name.set(teacher,"refine");
System.out.println(name.get(teacher));
} catch (InstantiationException |IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
调用运行时类指定方法
- getDeclaredMethod():获取指定的某个方法.参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表
- method.setAccessible(true):设置方法为可访问的
- method.invoke():参数1:方法的调用者;参数2:给方法形参赋值的实参。返回值即为对应类中调用的方法的返回值。
@Test
public void test2(){
Class<Teacher> clazz = Teacher.class;
//创建运行时类的对象
try {
Teacher teacher = clazz.newInstance();
// getDeclaredMethod():获取指定的某个方法.参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表
Method show = clazz.getDeclaredMethod("show",String.class);
show.setAccessible(true);
// 调用方法的invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参
// invoke()的返回值即为对应类中调用的方法的返回值。
Object china = show.invoke(teacher, "china");
System.out.println(china);
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException |
InvocationTargetException e) {
throw new RuntimeException(e);
}
}
调用运行时类指定构造器
- clazz.getDeclaredConstructor():参数:指明构造器的参数列表
@Test
public void test3(){
Class<Teacher> clazz = Teacher.class;
try {
Teacher teacher = clazz.newInstance();
Constructor<Teacher> constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Teacher lucy = constructor.newInstance("LUCY");
System.out.println(lucy);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}