一.反射机制
一、反射的概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
Java反射机制研究及应用
Java反射机制提供的功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解 生成动态代理
二.Class类
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。
类的加载过程
类的加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口(即引用地址)。所有需要访问和使用类数据只能通过这个Class对象。这个加载的过程需要类加载器参与。
类的链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
类的初始化:
● 执行类构造器【clinit】()方法的过程。类构造器【clinit】()方法是由编译期自动收集类中 所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信 息的,不是构造该类对象的构造器)。
● 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类 的初始化。
● 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。
类初始化
(即通过new出来的,或者通过反射获取的一定会发生类的初始化)
类的主动引用(一定会发生类的初始化)
- 当虚拟机启动,先初始化
main
方法所在的类 new
一个类的对象- 调用类的静态成员(除了final常量)和静态方法
- 使用
java.lang.reflect
包的方法对类进行反射调用 - 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化
- 当通过子类引用父类的静态变量,不会导致子类初始化
- 通过数组定义类引用,不会触发此类的初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
三.反射的使用
一.获取Class对象的三种方式
1. 调用运行时类的属性:.class
前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠, 程序性能最高
示例: Class clazz1 = String.class;
2. 通过运行时类的对象,调用getClass()
前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
示例:Class clazz = “www.atguigu.com”.getClass();
3.调用Class的静态方法:forName(String classPath)
前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName() 获取,可能抛出ClassNotFoundException
示例: Class clazz = Class.forName(“java.lang.String”);
public class study1 {
public static void main(String[] args) throws ClassNotFoundException {
//方法一:通过类的属性
Class c1 = Student.class;
System.out.println(c1.getName()); //全类名:org.example.reflection.Student
System.out.println(c1.getSimpleName()); //类名:Student
//方法二:通过类的对象
Student s=new Student();
Class c2 = s.getClass();
//方法三:调用Class静态方法
Class c3 = Class.forName("org.example.reflection.Student");
System.out.println(c1==c2); //true
System.out.println(c2==c3); //true
System.out.println(c1==c3); //true
}
}
二.获取构造器方法
@Test
public void testGetConstructors() throws NoSuchMethodException {
//获取这个类的Class对象
Class c = Cat.class;
Constructor[] constructors = c.getConstructors(); //获取类的全部构造器(只能获取public修饰的)
for (Constructor constructor : constructors) {
System.out.println(constructor.getName()+"->"+constructor.getParameterCount());
}
Constructor[] declaredConstructor = c.getDeclaredConstructors(); //获取类的全部构造器(包括private修饰的)
for (Constructor constructor : declaredConstructor) {
System.out.println(constructor.getName()+"->"+constructor.getParameterCount());
}
//获取有参数的构造器
Constructor declaredConstructor1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(declaredConstructor1.getName()+"--->"+declaredConstructor1.getParameterCount());
}
//获取无参构造器
Constructor declaredConstructor = c.getDeclaredConstructor();
System.out.println(declaredConstructor.getName()+"--->"+declaredConstructor.getParameterCount());
declaredConstructor.setAccessible(true);//禁止检查权限
Cat cc = (Cat)declaredConstructor.newInstance();//对象初始化
System.out.println(cc);
//获取有参数的构造器
Constructor declaredConstructor1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(declaredConstructor1.getName()+"--->"+declaredConstructor1.getParameterCount());
declaredConstructor1.setAccessible(true);//禁止检查权限
Cat cc1 = (Cat)declaredConstructor1.newInstance("哆啦A梦", 3);//对象初始化
System.out.println(cc1);
执行结果:
三.获取成员变量
@Test
public void testGetFields() throws NoSuchFieldException, IllegalAccessException {
Class c=Cat.class;
//获取所有成员变量(包括private)
Field[] fields = c.getDeclaredFields(); //getField() 只能获取public修饰的成员变量
for (Field field : fields) {
System.out.println(field.getName()+"---->"+field.getType());
}
//定位某个成员变量
Field name = c.getDeclaredField("name");
System.out.println(name.getName()+"---->"+name.getType());
//赋值
Cat cat=new Cat();
name.setAccessible(true);
name.set(cat,"哆啦A梦");
System.out.println(cat);
}
执行结果:
四.获取成员方法
@Test
public void testGetMethods() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class c=Cat.class;
//获取所有方法
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName()+"--->"
+method.getParameterCount()+"--->"
+method.getReturnType());
}
//获取某个方法对象
Method run=c.getDeclaredMethod("run");
System.out.println(run.getName()+"--->"
+run.getParameterCount()+"--->"
+run.getReturnType());
Cat cat=new Cat();
run.setAccessible(true);
Object rs = run.invoke(cat);
System.out.println(rs);
}
执行结果: