在我们了解了反射机制后,我们知道Class对象是反射机制的关键,下面介绍的反射的使用方法同样是Class类为重点。
为方便阅读,我将上篇最重要的三阶段图也放在这篇里。
使用Class类中的静态方法forName()
使用这种方式获取Class对象,需要明确该类的全限定名
多用与结合配置文件的使用,通过在配置文件里利用键值对等方法来编写全类名
程序读取文件,得到全类名,来得到Class对象
简单点就是从properties文件提取类名方式使用
这个方法对应着源代码阶段
// budiu包下的Dog类所对应的Class对象
Class cls=Class.forName("budiu.Dog");
调用类的静态变量class
在有重名的类时,一定要检查清楚自己引用的类是正确的
多用于参数传递,类似于继承等使用
这个方法对应类加载器阶段
Class cls1=Dog.class;
调用对象的getClass()
方法
这个方法是你编写类时默认就有的(Object类里面的方法),不用自己写,类似于toString方法,你没编写它也会有一个默认的
多用于获取对象的字节码形式,将类名放入porperties等类型的文件
这个方法对应运行时阶段
//调用对象方法来获取
Dog dog=new Dog();
Class cls2=dog.getClass();
在程序运行时,同一个类只会被加载一次,也就是只生成一个对应的Class对象。假如说我前面的三种获取Class对象方式都是在一个程序中所获取,那么cls,cls1,cls2的地址也会相同。
上面已经说到我们常用的操作主要就是与成员变量、构造器方法、成员方法有关,还有一个获取类名称也较为常用,其他的可以暂时不深究。
为方便举例,我们仍使用上面所创建的Dog类:
package budiu;/*Author:l
Explain:
Version:1.0*/
public class Dog {
//属性
public String name;
private int age;
//公共构造器
public Dog(){}
public Dog(int age){
this.age=age;
}
//私有构造器
private Dog(String name){
this.name=name;
}
//get和set方法
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 void play(){
System.out.println("捡球");
}
private void sleep(){
System.out.println("睡觉");
}
}
getName()
方法:返回类的名称。它可以在需要获取类名时使用,例如在日志记录或调试过程中。
其实本人认为toString方法是相同的效果,但它存在肯定是有它的道理的
Class cls=Class.forName("budiu.Dog");
String cls_name=cls.getName();
System.out.println(cls_name);
getField()
方法:需要在括号里传入你要获取的成员变量名,返回对应的成员变量的Field对象,只能获得公共成员变量
getDeclaredField()
方法:需要在括号里传入你要获取的成员变量名,返回对应的成员变量的Field对象,可以所有成员变量,不受访问权限修饰符影响
getField()
方法:返回所有成员变量的Field对象数组,但不包括私有(private修饰)成员变量
getDeclaredFields()
方法:返回所有成员变量的Field对象数组,包括私有(private修饰)成员变量
//常用的获取成员属性的四种方法
Field[] fields=cls.getFields();
Field[] declaredFields=cls.getDeclaredFields();
Field field1=cls.getField("name");
Field field2=cls.getDeclaredField("age");
获取到的Field对象可以用来获取和设置对应成员变量的值。如果获取的Field对应的成员变量是私有的,通常情况下是不能直接使用的,因为我们只是获取到到了它的Field对象而已,私有成员变量只能在它们所属的类内部访问。
Class cls=Class.forName("budiu.Dog");
String cls_name=cls.getName();
System.out.println(cls_name);
//常用的获取成员属性的四种方法
Field[] fields=cls.getFields();
Field[] declaredFields=cls.getDeclaredFields();
Field field1=cls.getField("name");
Field field2=cls.getDeclaredField("age");
//创建一个实例化对象
Dog dog=new Dog();
//原有的age属性是私有的
//要用这个方法去无视访问权限
field2.setAccessible(true);
//将Dog类的实例化对象dog的私有属性age设置值和获取值
field2.set(dog,15);
field2.get(dog);
然而,通过反射机制,我们可以绕过访问权限限制来访问私有成员变量。在使用反射访问私有成员变量时,需要调用Field对象的setAccessible(true)
方法,以允许访问私有字段。然后,可以使用Field对象的get()
方法来获取私有成员变量的值,或使用set()方法来设置私有成员变量的值。
getConstructor()
:该方法用于获取当前Class所表示类的public修饰的构造器。
getDeclaredConstructor()
:该方法用于获取当前Class所表示类的public修饰的构造器。
你需要通过在括号里传入参数类型来获取指定构造器,没有就是获取无参构造器。
getConstructors()
: 该方法用于获取当前Class所表示类的public修饰的构造器。
getDeclaredConstructors()
: 该方法用于获取当前Class所表示类的所有构造器,无视访问权限。
//四种获取构造器的方法
Constructor constructor=cls.getConstructor();
Constructor declaredConstructor=cls.getDeclaredConstructor();
Constructor[] constructors=cls.getConstructors();
Constructor[] declaredConstructors=cls.getDeclaredConstructors();
为避免篇幅过长,这里只举私有构造器的使用
只需要利用newInstance()
方法和setAccessible()
方法即可。
//只举私有构造器的使用
//私有构造器
// private Dog(String name){
// this.name=name;
// }
//这里我不想遍历里面的构造器数组,直接用构造器传参特征来获取对应构造器
Constructor privateConstructor=cls.getDeclaredConstructor(String.class);
privateConstructor.setAccessible(true);
//利用newInstance即可构造并创建对象
Dog reflect_dog=(Dog) privateConstructor.newInstance("来福");
getMethod()
方法: 这个方法用于获取公共的方法。
getDeclaredMethod()
方法: 这个方法用于获取所有的方法,无论公共的还是非公共的。
getMethods()
方法:用于获取某个类的所有公共方法。
getDeclaredMethods()
方法:获取某个类的所有声明的方法。
//四种获取Method对象的方法
Method method=cls.getMethod("setName", String.class);
Method declaredMethod=cls.getDeclaredMethod("sleep");
Method[] methods=cls.getMethods();
Method[] declaredMethods=cls.getDeclaredMethods();
只要了解invoke()和setAccessible()方法即可,
这里以sleep()方法的执行为例
//私有方法原型
// private void sleep(){
// System.out.println("睡觉");
// }
//sleep方法的使用
declaredMethod.setAccessible(true);
declaredMethod.invoke(dog);
}
在学习初阶编程的时候,我们并不会频繁的使用反射,它虽然有着许多有点,但对于我们新手而言,代码复杂度也会一定程度上攀升。所以重点的是了解它的原理,这会为我们以后的框架学习带来更多感悟,记得老师曾经说过,反射机制是框架的灵魂所在。
顺便便把我做笔记的源码放在这,和上方的Dog类一起即可运行,注意全类名要改成自己的,包名应该用自己的包名。
package budiu;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
Class cls=Class.forName("budiu.Dog");//注意改成自己的包名
String cls_name=cls.getName();
//常用的获取成员属性的四种方法
Field[] fields=cls.getFields();
Field[] declaredFields=cls.getDeclaredFields();
Field field1=cls.getField("name");
Field field2=cls.getDeclaredField("age");
Dog dog=new Dog();
//原有的age属性是私有的
//这个必须得有
field2.setAccessible(true);
//将Dog类的实例化对象dog的私有属性age设置值和获取值
field2.set(dog,15);
field2.get(dog);
//四种获取构造器的方法
Constructor constructor=cls.getConstructor();
Constructor declaredConstructor=cls.getDeclaredConstructor();
Constructor[] constructors=cls.getConstructors();
Constructor[] declaredConstructors=cls.getDeclaredConstructors();
//只举私有构造器的使用
//私有构造器
// private Dog(String name){
// this.name=name;
// }
//这里我不想遍历里面的构造器数组,直接用构造器传参特征来获取对应构造器
Constructor privateConstructor=cls.getDeclaredConstructor(String.class);
privateConstructor.setAccessible(true);
//利用newInstance即可构造并创建对象
Dog reflect_dog=(Dog) privateConstructor.newInstance("来福");
//四种获取Method对象的方法
Method method=cls.getMethod("setName", String.class);
Method declaredMethod=cls.getDeclaredMethod("sleep");
Method[] methods=cls.getMethods();
Method[] declaredMethods=cls.getDeclaredMethods();
//私有方法原型
// private void sleep(){
// System.out.println("睡觉");
// }
//sleep方法的使用
declaredMethod.setAccessible(true);
declaredMethod.invoke(dog);
}
}