Java代码在计算机中经历的三个阶段
1.源代码阶段
.java源码文件 ---》.class字节码文件
2.Class类对象阶段
类加载器 ---》Class类对象(反射机制)
(Class类对象包括,成员变量Field[] fields + 构造方法Constructor[] constructors + 成员方法Method[] methods)
3.运行时阶段
Class类对象,创建对象
反射:将类的各个组成部分封装为其他对象,这就是反射机制。
反射的好处:1.可以在程序的运行过程中,操作这些对象
2.可以解耦,提高程序的可扩展性
获取Class对象的方式:
1.源代码阶段
Class.forName("全类名"):将字节码文件加载进内存,返回Class类对象
* 多用于配置文件,将类名定义在配置文件中。读取配置文件,加载类。
2.Class类对象阶段
类名.class:通过类名的属性class来获取
* 多用于方法的参数的传递。
3.运行时阶段
对象.getClass():此方法在Object类中定义。
* 多用于对象的获取字节码的方式。
//1.
Class cls1= Class.forName("useless.Person");
System.out.println(cls1);
//2.
Class cls2= Person.class;
System.out.println(cls2);
//3.
Person p=new Person();
Class cls3=p.getClass();
System.out.println(cls3);
注:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
Class对象的使用
获取功能:1.获取成员变量们,getxxx()...getDeclaredFields()能获取private修饰的变量
2.获取构造方法们,
3.获取成员方法们,
4.获取类名
利用反射获取成员变量
设置和获取public,protected修饰的成员变量
Class personClass=Person.class;//获取Class类对象
Person p=new Person();
Field field = personClass.getField("name");//获取成员变量
field.set(p,"chenkai");//为一个对象的成员变量设置值
System.out.println(field.get(p));//获取一个对象的成员变量的值
设置和获取private修饰的成员变量
Field ageField = personClass.getDeclaredField("age");
ageField.setAccessible(true);//忽略安全检查,开启暴力反射,访问private变量
ageField.set(p, 10);
System.out.println(ageField.get(p));
利用反射获取构造方法
利用获取的构造方法生成新实例
Class personClass=Person.class;
Constructor constructor=personClass.getConstructor(String.class,int.class);
Object person=constructor.newInstance("lilili",29);
利用空构造函数生成新实例的另一种方法
Object person1=Person.class.newInstance();
利用反射获取方法
获取和执行方法
Class personClass=Person.class;
Person person=new Person("ck",18);
Method setAge=personClass.getMethod("setAge",int.class);//获取有参方法
Method getAge=personClass.getMethod("getAge");//获取无参方法
setAge.invoke(person,99);//执行有参方法
System.out.println(getAge.invoke(person));//执行无参方法
注:
personClass.getMethods();//此方法也会获取其父类的public方法
反射的应用
需求:一个简化框架,不改变该框架类的代码,并能创建任意对象,执行任意方法。
实现需要:配置文件,反射
步骤:
1.将要创建的对象的全类名和需要执行的方法定义在配置文件中
2.在程序中加载读取配置文件
3.使用反射技术来加载类文件进内存
4.创建方法
5.执行方法
代码:
//1.加载配置文件
Properties pro=new Properties();//创建对象
ClassLoader classLoader=ReflectTest.class.getClassLoader();//获取类加载器
InputStream is=classLoader.getResourceAsStream("useless/pro.properties");//通过类加载器获取配置文件
pro.load(is);
//2.获取配置文件中的数据
String className=pro.getProperty("className");
String methodName=pro.getProperty("methodName");
//3.加载该类进内存
Class myClass=Class.forName(className);
//4.创建对象,执行方法
Object obj=myClass.newInstance();
Method method=myClass.getMethod(methodName);
method.invoke(obj);
配置文件:
className=useless.Student
methodName=sleep
优点:
改配置文件更方便,不会影响已有代码,扩展性也更强。