目录
一、概念:
java反射机制是,在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用这个对象的任意方法和属性;这种动态获取类信息和动态调用对象方法的功能,称为java语言的反射机制。
二、理解:
1)状态:运行状态
2)功能:
a)对于任意一个类,都能够知道这个类的所有属性和方法;
b)对于任意一个对象,都能够调用这个对象的任意方法和属性;
说明:在运行期间,如果要获取某个类的class对象,java虚拟机(JVM)会检查该类的class对象是否已被加载。如果没有被加载,JVM会根据类的完全路径名称找到对应的.class文件并加载到内存中并生成对应的class对象。一旦某个类型的class对象已被加载到内存中,就可以用这个class对象来产生该类型的所有实例对象。
三、例子:
1、获取字节码信息的4种方式
1)通过实例的getClass()方法:
Person p1 = new Person();
Class c1 = p1.getClass();
2)通过实例的class属性:
Class c2 = Person.class;
3)通过Class.forName方法(最常用):
Class c3 = Class.forName("com.luke.Person");
4)通过类加载器的loadClass方法:
ClassLoader classLoader = Test.class.getClassLoader();
Class c4 = classLoader.loadClass("com.luke.Person");
2、Class类的实例的种类
1)普通类:
Class c1 = Person.class;
2)接口:
Class c2 = Comparable.class;
3)注解:
Class c3 = Override.class;
4)数组:
int[] arr1 = {1,2,3};
int[] arr2 = {4,5,6};
int[] arr3 = {7,8,9,10};
Class c4 = arr1.class;
Class c5 = arr2.class;
Class c6 = arr3.class;
System.out.println(c4 == c5); // true 相同纬度的数组为true
System.out.println(c4 == c6); // false 不相同纬度的数组为false
5)基本数据类型:
Class c7 = int.class;
6)void:
Class c8 = void.class;
3、获取构造器
1)获取所有public访问修饰符修饰的构造器
Constructor[] constructors = cls.getConstrutors();
2)获取所有访问修饰符修饰的构造器
Constructor[] constructors = cls.getDeclaredConstrutors();
3)获取某个特定的构造器
// getConstrutor(Class<?>... parameters)
// 默认空构造器
Constructor constructor1 = cls.getConstrutor();
// 有一个int参数的构造器
Constructor constructor2 = cls.getConstrutor(int.class);
// 有一个double参数、int参数的构造器
Constructor constructor3 = cls.getConstrutor(double.class,int.class);
// 同理,获取私有构造器
// 私有空构造器
Constructor constructor4 = cls.getDeclaredgetConstrutor();
// 有一个私有int参数的构造器
Constructor constructor5 = cls.getDeclaredgetConstrutor(int.class);
// 有一个私有double参数、int参数的构造器
Constructor constructor6 = cls.getDeclaredgetConstrutor(double.class,int.class);
4、创建对象
// 使用无参构造器创建对象
Object o1 = constructor1.newInstance();
// 使用有一个int参数的构造器创建对象
Object o2 = constructor2.newInstance(2);
// 使用有double.class,int.class的构造器创建对象
Object o3 = constructor2.newInstance(12.56,10);
5、获取属性和对属性进行赋值
1)获取所有当前类和父类中public修饰的属性
Field[] fields = cls.getFields();
2)获取所有当前类和父类中的属性
Field[] fields = cls.getDeclaredFields();
3)获取指定的属性
// 获取public的名称为name的属性
Field field = cls.getField("name");
// 获取private的名称为password的属性
Field field = cls.getDeclaredField("password");
4)获取属性的具体结构
// 1、获取属性的访问修饰符,是一个整数
int modifier = field.getModifiers(); // 1
// 可以通过Modifier.toString(modifier值)
System.out.println(Modifier.toString(modifier)); // 输出 public
// 2、获取属性的类型class对象
Class type = field.getType();
// 3、获取属性的名称
String name = field.getName();
说明:Modifier类是Java语言用于描述各种访问修饰符的类,各种访问修饰符有自己独有的int值表示对应的类型的访问修饰符,其中public使用1表示,static使用8表示,假如filed.getModifiers方法返回9,则表示由public和static同时修饰,可以使用Modifier.toString(modifier)打印出信息来;
5)给属性赋值
// 获取类的class对象
Class cls = Class.forName("com.luke.Person");
// 获取name属性
Field name = cls.getField("name");
// 给属性赋值时,必须要有实例对象
// 实例化对象
Object person = cls.newInstance();
// 给person实例name属性赋值
name.set(person,"张三");
6、获取方法和调用方法
1)获取访问修饰符public修饰的所有方法
Method[] methods = cls.getMethods();
2)获取所有访问修饰符修饰的所有方法
Method[] methods = cls.getDeclaredMethods();
3)获取指定方法
// getMethod(String name,Class<?>... parameters)方法
// 获取无参的play方法
Method method1 = cls.getMethod("play");
// 获取有String类型的参数的play方法
Method method2 = cls.getMethod("play",String.class);
4)获取方法的具体结构
// 获取注解前必须要指定方法
Method method = cls.getMethod("play");
// 获取方法名称
String name = method.getName();
// 获取方法的访问修饰符
int modifier = method.getModifiers();
System.out.println(Modifier.toString(modifier));
// 获取方法返回类型
Class returnType = method.getReturnType();
// 获取方法参数列表类型数组
Class[] parameterTypes = method.getParameterTypes();
// 获取方法的所有runtime类型的注解,即只有注解的@Retention(RetentionPolicy.RUNTIME)才能被获取
Annotation[] annotations = method.getAnnotations();
// 获取异常数组
Class[] exceptionTypes = method.getExceptionTypes();
5)调用方法
// 获取类的class对象
Class cls = Class.forName("com.luke.Person");
// 获取无参play方法
Method play1 = cls.getMethod("play");
// 获取有String类型参数的play方法
Method play2 = cls.getMethod("play",String.class);
// 调用方法时,必须要有实例对象
// 实例化对象
Object person = cls.newInstance();
// 调用person实例的无参play方法
play1.invoke(person);
// 调用person实例的有一个String类型参数的play方法
play2.invoke(person,"basketBall");
7、获取类的接口、所在包、注解
Class cls = Class.forName("com.luke.Person");
// 1、获取当前类的接口
Class[] interfaces = cls.getInterfaces();
// 获取父类的接口
Class superCls = cls.getSuperClass();
Class[] superInterfaces = superCls.getInterfaces();
// 2、获取当前类所在包
Package package = cls.getPackage();
// 3、获取当前类RUNTIME类型的注解
Annotation[] annotations = cls.getAnnotations();