Java反射机制
在我们了解Java反射之前先思考什么是正射,即程序正常运行的过程。
正射:程序在编译之前就已经被Java虚拟机加载,加载完了所有需要的类。
反射:在编译时并不知道哪个类被加载,在运行时才加载、调用。
总结下来什么是反射机制:在程序运行时,才会动态获取类的完整结构信息以及调用对应方法的功能。
Java反射常用的类
Class类:反射的核心类,所有操作都是围绕该类来生成的,通过Class类可以获取类的属性、方法。
Field类:表示类的属性。
Method类:表示类的方法。
Constructor类:表示类的构造方法。
反射的应用
首先创建一个Person类
package entity;
public class Person {
private String name;
public int age;
private char gender;
public Person() {}
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
private Person(String name) {
this.name = name;
}
private void welcome(String tips){
System.out.println(tips);
}
public void happy(String name,int age,char gender){
System.out.println(name + age + gender);
}
private int age(int num){
return num;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
}
一、获取Class对象
1、调用对象的getClass方法
Person p = new Person();
Class c = p.getClass();
//注:getClass()是Object类中的一个方法,该方法可以返回该对象所属类对应的Class对象。
2、调用类的class属性
Class c = Person.class;
//注:调用类的class属性可以获取该类对应的Class对象,但是要在编译期间就知道类的名称。
3、使用Class类的forName静态方法
Class c = Class.forName("entity.Person");
//注:Class类的forName()方法也可以获取对应的Class对象,该方法需要传入字符串参数,该字符串参数的值是类的全名,要在类名前加完整的包名。
补:获取父类对象
假设Person类是某个类的子类,则我们可以通过Person类来获取其父类的Class对象
Class c1 = c.getSuperclass(); //c为Person的Class对象
二、创建对象
首先获取Person的Class对象,采用上述方法中的其中一种即可
Class c = Person.class;
1、使用Class对象的newInstance方法来创建对象
Person p = (Person)c.newInstance();
//注:该方式需要该Class对象的对应类有默认的构造方法,执行newInstance()方法实际就是利用默认的构造方法来创建类的实例。
2、使用Constructor对象的newInstance方法创建对象
Constructor t = c.getConstructor(String.class,int.class,char.class);
Person p = (Person) t.newInstance("任",18,'男');
System.out.println(p.toString());
//通过这种方式可以选择使用某个类的指定构造方法来创建实例,需要提供给getConstructor()参数类型
三、访问Class对应类所包含的属性
Class c = Person.class; //获取类的Class对象
//Field[] fields = c.getFields(); //getFields()获取Person对象的所有public属性
Field[] fields = c.getDeclaredFields(); //getDeclaredFields()获取所有属性,无论私有公有
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i].getName()); //获取属性名
System.out.println(Modifier.toString(fields[i].getModifiers())); //获取属性修饰符
}
//Field field = c.getField("age"); //获取指定的public属性,age为属性名
Field field = c.getDeclaredField("name"); //获取指定的属性,无论公有私有,getDeclaredField("属性名")
field.setAccessible(true); //当获取私有属性时,必须将setAccessible()方法设置为true,setAccessible()对获取到的属性设置访问权限
Person p = new Person();
field.set(p,"张三"); //对属性进行赋值
System.out.println(p.toString());
四、访问Class对应类所包含的构造方法
Class c = Person.class; //获取类的Class对象
Constructor[] constructors = c.getConstructors(); //获取所有public构造方法
//Constructor[] constructors = c.getDeclaredConstructors(); //获取Person类中的所有构造方法
for (int i = 0; i < constructors.length; i++) {
System.out.println(constructors[i].getName());
System.out.println(constructors[i].getModifiers());
Class[] parameterTypes = constructors[i].getParameterTypes(); //获取参数类型
for (int j = 0; j < parameterTypes.length; j++) {
System.out.println(parameterTypes[i].getName()); //获取参数名
}
System.out.println();
}
//Constructor constructor = c.getConstructor(); //获取public构造方法,支持有参无参,想指定什么构造方法,只需将对应参数填入即可
//getDeclaredConstructor()获取Person类任意一个构造方法,不论公私
Constructor constructor = c.getDeclaredConstructor(String.class,int.class,char.class);
constructor.setAccessible(true); //访问私有,参数为true,允许访问
Person person = (Person) constructor.newInstance("任",24,'男'); //通过构造方法的newInstance方法进行赋值
System.out.println(person.toString());
五、访问Class对应类所包含的非构造方法(普通方法)
Person person = new Person();
Class t = person.getClass();
Method[] methods = t.getMethods(); //获取所有public方法
//Method[] methods = t.getDeclaredMethods(); //获取所有方法
for (int i = 0; i < methods.length; i++) {
System.out.println(Modifier.toString(methods[i].getModifiers()));
System.out.println(methods[i].getName());
Class[] parameterTypes = methods[i].getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
System.out.println(parameterTypes[j].getName());
}
System.out.println();
}
//Method method = t.getMethod("happy", String.class,int.class,char.class);
//getMethod()获取指定public方法,happy为方法名,后面为参数
Method method = t.getDeclaredMethod("welcome", String.class); //getDeclaredMethod()获取指定方法,无论公私
System.out.println(Modifier.toString(method.getModifiers()));
method.setAccessible(true);
method.invoke(person,"阿门"); //invoke()方法进行赋值