Java的反射:(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键
- 反射机制允许程序在执行期间借助于ReflectionAPI取得任何类的内部信息,比如成员变量,构造器,成员方法等,并能操作对象的属性及其方法,反射在设计模式和框架底层都会用到
- 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象)这个对象包含了类的完整信息结构,通过这个对象,就可以了解全部信息,Class对象犹如镜子的反射人物对象,在镜子中能获取全部的Class信息
Java加载示意图:
简单来说反射就犹如人照镜子一样,能通过一个Class对象了解全部信息
为什么要使用反射:
- 反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。
- 通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。
- 使用反射机制能够在运行时构造一个类的对象,判断一个类所具有的成员变量和方法,调用一个对象方法。
- 反射机制还是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。正因为反射,Java才被称为动态语言。
Class类:
- Class也是类,因此也继承Object类
- Class类对象不是new出来的,而是系统创建的
- 对于某个Class对象,在内存中只存在一份,因为只类加载一次
- 每个类的实例对象都会记得自己是有哪个Class实例所构成的
- 通过Class对象可以完整的得到一个类的完整结构
- Class对象是存放在堆区的
- 类的字节码二进制数据,是在方法区的,有的地方称为类的元数据
几种获取Class的方式:
import org.testng.annotations.Test;
public class TestReflection01 {
@Test
public void Test() throws ClassNotFoundException {
/*
1:通过配置文件获取Class对象
*/
Class<?> aClass = Class.forName("TestStudent");
System.out.println("第一种方法通过配置文件:"+aClass.getName());
/*
2:通过类名.Class获取Class对象
*/
Class<TestStudent> testStudentClass = TestStudent.class;
System.out.println("第二种通过类名.class获取Class对象:"+testStudentClass.getName());
/*
3:通过实例对象,来获取Class对象
*/
TestStudent testStudent = new TestStudent();
System.out.println("第三种通过实例获取Class对象:"+testStudent.getClass().getName());
/*
4:通过类加载器获取Class对象
*/
Class<?> testStudent1 = TestStudent.class.getClassLoader().loadClass("TestStudent");
System.out.println("第四种通过类加载器:"+testStudent.getClass().getName());
}
}
class TestStudent{
/*
四个不同的属性
*/
private String name;
protected int age;
double height;
public char sex ;
public TestStudent(){}
}
运行结果:
哪些类型有Class对象:
- 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
- interface:接口
- 数组
- Enum:枚举
- Annotation:注解
- 基本数据类型
- 方法(void)等
运用Class,通过反射获取属性:
@Test
public void TestGetFileds() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
//获取一个Class对象
Class<?> aClass = Class.forName("TestStudent");
//使用newInstance实例化一个对象
TestStudent student = (TestStudent) aClass.newInstance();//转成TestStudents类型
//通过反射获取属性
//使用.getField()获取公有Sex的属性
Field sex = aClass.getField("sex");
System.out.println(sex.getName());
System.out.println(sex.get(student));//取得该student实例化对象的sex值
/*
通过反射获取私有的属性需要进行一步暴破操作,因为私有的属性反射不能够直接获取,需要使用
*/
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);//将私有的属性设置为可得到的,也就是暴破操作
System.out.println(name+"\t"+name.get(student));
//修改属性
name.set(student,"Jerry");//传入的参数为修改的对象,已经修改的参数值
System.out.println(name.get(student));
}
@SuppressWarnings("ALL")
class TestStudent{
/*
四个不同的属性
*/
private String name = "Tom";
protected int age = 20;
double height = 177;
public char sex = '男';
public TestStudent(){}
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 double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
运行结果:
通过反射获取方法:
@Test
public void TestGetMethod() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//获取一个Class对象
Class<?> aClass = Class.forName("TestStudent");
//使用newInstance实例化一个对象
TestStudent student = (TestStudent) aClass.newInstance();//转成TestStudents类型
//获取公有的方法1
Method method1 = aClass.getMethod("method1");
method1.invoke(student);//调用该student对象的方法1
//获取私有的方法2 ,3 ,4,也要使用setAccessible(true)进行暴破操作
Method method4 = aClass.getDeclaredMethod("method4");
method4.setAccessible(true);
method4.invoke(student);
//剩下的还有一些方法就自己去测试吧
}
@SuppressWarnings("ALL")
class TestStudent{
/*
四个不同的属性
*/
private String name = "Tom";
protected int age = 20;
double height = 177;
public char sex = '男';
public TestStudent(){}
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 double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public void method1(){
System.out.println("这是public的方法1");
}
void method2(){
System.out.println("这是default的方法2");
}
protected void method3(){
System.out.println("这是protected方法3");
}
private void method4(){
System.out.println("这是private方法4");
}
@Override
public String toString() {
return "TestStudent{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
", sex=" + sex +
'}';
}
}
通过反射获取构造器创建实例:
@Test
public void TestGetConstructor() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//获取一个Class对象
Class<?> aClass = Class.forName("TestStudent");
Constructor<?> constructor = aClass.getConstructor();//获得一个public空参构造器
TestStudent testStudent = (TestStudent) constructor.newInstance();//实例化对象
System.out.println("这是公有的无参构造器:"+testStudent.toString());
//获得一个公有的带参构造器
Constructor<?> constructor1 = aClass.getConstructor(String.class,int.class,double.class);//传入参数的class对象
TestStudent testStudent1 = (TestStudent) constructor1.newInstance("Jerry",25,178.9);//实例化对象,传入参数
System.out.println("这是公有的有参构造器:"+testStudent1.toString());
//获取私有构造器
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);//暴破操作
TestStudent testStudent2 = (TestStudent) declaredConstructor.newInstance("Frank", 44);
System.out.println("这是私有的有参构造器:"+testStudent2.toString());
}
@SuppressWarnings("ALL")
class TestStudent{
/*
四个不同的属性,分别赋予不同初始值
*/
private String name = "Tom";
protected int age = 20;
double height = 177;
public char sex = '男';
public TestStudent(){}//空构造器
//带参构造器
public TestStudent(String name,int age,double height)
{
this.name =name;
this.age =age;
this.height = height;
}
//私有构造器
private TestStudent(String name,int age){
this.name = name;
this.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 double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
@Override
public String toString() {
return "TestStudent{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
", sex=" + sex +
'}';
}
}
运行结果:
总结:
public void AllMethod(){
/**
* 主要方法有这些
* Class.forName()通过配置路径获取一个Class对象
* 使用newInstance()实例化一个对象
* :getName:获取全类名
* :getSimpleName:获取简单类名
* :getPackage()取得相应的包
* :getSuperClass:以Class形式返回父类信息
* getInterfaces:以Class[形式返回接口信息
* getAnnotations:以Annotation[]形式返回注解信息
*
*
* setAccessible(true),反射暴破操作,将私有的属性或者方法变为反射可得到的,因为私有的属性反射不能够直接获取,会发生NoSuchFieldException异常
* Field
* :getField:获取一个本类或者父类的属性,传入参数为属性名
* :getDeclaredField:获取本类中的一个属性,传入参数为属性名
* :getFields:获取所有public修饰的属性,包含本类以及父类的
* :getDeclaredFields:获取本类中所有属性
* :getFields:获取所有public修饰的属性,包含本类以及父类的
*
* Method
* :getMethod:获取一个本类或者父类的方法,传入参数为属性名
* :getDeclaredMethod:获取本类中一个方法,传入参数为属性名
* :getMethods:获取所有public修饰的方法,包含本类以及父类的
* :getDeclaredMethods:获取本类中所有方法
* :method.invoke(Object o)调用方法
*
* Constructor
* getConstructor()获取一个公有的构造器
* getDeclaredConstructor()获取一个本类的构造器,根据传入参数的不同去匹配相应的构造器
* getConstructors: 获取所有public修饰的构造器,包含本类以及父类
* getDeclaredConstructors:获取本类中所有构造器
* constructor.newInstance()实例化对象
* 还有很多很多方法,这里就不一一列举了
*/
}
以上就是全部内容啦,如有错误,请多海涵,谢谢啦。