反射机制
类加载:
当一个程序要使用某个类时,如果类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化,如果不发生意外,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或类初始化。
java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息和动态调用对象的方法的功能称为java语言反射机制。
优点:可以在程序运行过程中,操作这些对象,动态加载类,可以解耦,提高代码灵活性。(反射是框架的灵魂)
缺点:反射相当于一系列解释操作,通知JVM要做的事,性能比直接的java代码要慢的多,并且动态操作改变类的属性同时增加安全隐患。
框架是半成品软件,可以在框架的基础上进行软件开发,简化编码。
反射将类的各个组成部分封装为其他对象,这就是反射机制。
获取class对象的方式:
1,Class.forName(“全类名”):将字节码文件加载到内存中,返回class对象多用于配置文件,将类名定义在配置文件中,读取文件,加载类。
2,类名.class:通过类名属性class获取,多用于参数的传递。
3,对象.getClass():getClass()方法在Object类中定义,多用于对象获取字节码的方式。
结论:同一个字节码文件(*class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
第一种情况:
package com.wzc;
public class Student {
}
package com.wzc;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
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 Person(){
}
}
package com.wzc;
//获取字节码Class对象的三种方式
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
// Class.forName("全类名"):将字节码文件加载到内存中,返回Class对象。
// Class.forName("全类名")
Class aClass = Class.forName("com.wzc.Person");
System.out.println(aClass);
// 类名.class:通过类名的属性class获取
Class personClass = Person.class;
System.out.println(personClass);
// 对象.getClass():getClass()方法在Object类中定义着
Person p = new Person();
Class aClass1 = p.getClass();
System.out.println(aClass1);
// 比较这三个对象,如果都是true,说明三者指向同一个对象
System.out.println(aClass == aClass1);
System.out.println(aClass == personClass);
Class studentClass = Student.class;
System.out.println(studentClass == aClass);
// 每个字节码文件所对应的类对象都不相同
}
}
// 得出结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次
// 不论哪种方式获取的Class对象都是同一个
Class对象功能:
获取功能:
获取成员变量们
Field[] getFields():获取所有public修饰的成员变量
Field getField(String name):获取指定名称的public修饰的成员变量
Field[] getDeclaredFields()
Field getDeclaredField(String name)
获取构造方法们
Constructor <>[] getConstructors()
Constructor<> get Constructor(类<>…parameterTypes)
Constructor <>[] getDeclaredConstructor(类<> …parameterTypes)
Constructor<> getDeclaredConstructors()
获取成员方法们
Method[] getMethods()
Method getMethod(String name,类<>… parameterTypes)
Method[] getMethods()
Method getMethod(String name,类<>… parameterTypes)
获取类名
String getName()
获取成员变量:
package com.wzc;
public class Person {
private String name;
private int age;
public String a;
protected String b;
String c;
private String d;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
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 Person(){
}
}
package com.wzc;
import java.lang.reflect.Field;
public class ReflectDemo2 {
public static void main(String[] args) throws Exception{
// 1.获取Person的Class对象
Class PersonClass = Person.class;
// 获取成员变量们
Field[] fields = PersonClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("----------------");
Field field1 = PersonClass.getField("a");
// Field :成员变量 操作:1,设置值 2,获取值 3,暴力反射
// 获取成员变量a的值
Person p = new Person();
Object value = field1.get(p);
System.out.println(value);
// 设置a的值
field1.set(p,"wang");
System.out.println(p);
System.out.println("-----------------");
// Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
Field[] declaredFields = PersonClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
// Field[] getDeclaredFields(String name):
Field d = PersonClass.getDeclaredField("d");
// 忽略访问权限修饰符的安全检查
// 使用暴力反射
d.setAccessible(true);
Object o = d.get(p);
System.out.println(o);
}
}
获取构造方法们:
package com.wzc;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception{
// 1.获取Person的Class对象
Class PersonClass = Person.class;
// 获取构造方法们,构造方法:1,创建对象
// Constructor<T> getConstructor(类<>... parameterType)
Constructor constructor = PersonClass.getConstructor(String.class, int.class);
System.out.println(constructor);
// 创建对象
Object wang = constructor.newInstance("wang", 23);
System.out.println(wang);
System.out.println("-----------------");
// 如果使用空参数构造方法创建对象,操作可以简化:class对象的newInstance方法
Object o = PersonClass.getConstructor().newInstance();
System.out.println(o);
}
}
获取成员方法们:
package com.wzc;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectDemo4 {
public static void main(String[] args) throws Exception{
// 1.获取Person的Class对象
Class PersonClass = Person.class;
//Method:1,执行方法:Object invoke(Object obj,Object... args)
// 2,获取方法名称:getName()
//获取指定名称的方法
Method eat_method = PersonClass.getMethod("eat");
Person p = new Person();
// 执行方法
eat_method.invoke(p);
Method eat_method2 = PersonClass.getMethod("eat", String.class);
eat_method2.invoke(p,"饭");
System.out.println("---获取所有public修饰的方法---");
Method[] methods = PersonClass.getMethods();
for (Method method : methods) {
System.out.println(method);
String name = method.getName();
System.out.println(name);
// method.setAccessible(true);
}
// 获取类名
String name = PersonClass.getName();
System.out.println(name);
}
}
package com.wzc;
public class Person {
private String name;
private int age;
public String a;
protected String b;
String c;
private String d;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
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 Person(){
}
public void eat(){
System.out.println("吃");
}
public void eat(String food){
System.out.println("吃"+food);
}
}
反射案例:
感受反射魅力所在 需求:写一个“框架”,在不改变该类的任何代码的前提下,可以帮助我们创建任意类的对象,并且执行其中任意方法
实现:
1,配置文件
2,反射
步骤:
1,将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2,在程序中加载读取配置文件
3,使用反射技术来加载类文件进内存
4,创建对象
5,执行方法
改配置文件的方式可以让程序扩展性更强
首先创建一个配置文件
package com.wzc;
public class Student {
public void sleep(){
System.out.println("睡觉");
}
}
package com.wzc;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
import static java.lang.Class.forName;
//框架类
public class ReflectTest {
public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
// 可以创建任意类的对象,可以执行任意方法
/*
前提是不能改变该类的任何代码,所以不能直接创建对象调用
*/
//1,加载配置文件
// 创建properties对象
Properties pro = new Properties();
// 加载配置文件,转化为一个集合
// 获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
pro.load(resourceAsStream);
// 获取配置文件中定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
// 加载该类进内存
Class aClass = forName(className);
// 创建方法
Method method = aClass.getMethod(methodName);
// 传入对象,执行方法,由于是java15,所以类对象的newInstance方法过时了,所以这样传
method.invoke(aClass.getDeclaredConstructor().newInstance());
}
}