文章目录
- 什么是反射
- Class类
- Java类动态加载
- 访问字段
- 调用方法
- 调用构造方法
什么是反射
在java程序中,我们会在方法区中存储类信息,类信息包括变量、方法、对象、父类子类等等,那么我们如何获取这个类信息呢?就用到了反射
定义:反射(Reflection
)是一种获取类信息的能力
我们一般会在Java程序运行期间,对某个实例对象一无所知的请情况下如何调用该对象内部方法的问题
原理:在Java程序运行的过程中,JVM加载完一个类之后,堆内存中就会产生一个该类的Class
对象,这个对象有且只有一个,这个class
对象包含了该类的完整结构信息(变量、方法…)
优缺点
- 优点:可以动态的创建和使用对象,反射机制是Java框架的底层核心
- 缺点:使用反射的基本是解释执行,对程序执行速度有影响
Class类
Class
也是一个类,类名就叫Class
,因此也继承Object
类- 又JVM在加载类时自动创建
- 堆内存中只存在某一个类的唯一
Class
对象,类只会加载一次 - 每个类的实例对象都会知道自己对应的
Class
对象 - 类的字节码二进制数据,是存放在方法区的,又称为
类的元数据
(包括方法代码、变量名、方法名、访问权限等等)
几个获取类信息的方法
创建一个Student
类,包含一些不同修饰符修饰的变量和方法
public class Student {private String name = "zhangsan";public Integer age = 18;Character sex = '男';protected Double height = 180.5;public String color = "Blue";public void run(){}private int getAge(int age){return age;}void aaa(String name, Integer height){}protected void hh(String name, int age){}
}
由于JVM为每个加载的类class
创建了对应的Class
类对象,并在实例中保存了该类class
的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class
类对象,我们就可以通过这个Class
类对象获取到其对应的类class
的所有信息。这种通过Class
实例获取类class
信息的方法称为反射(Reflection)。
获取类信息的几个方法:
方法1:通过类class
中的静态变量class
直接获取
public class Test {public static void main(String[] args) throws Exception {// 想要获取类信息就必须先进入类对象阶段 Class class = Student.class; // class是Student类中的一个变量}
}
方法2:如果我们有一个类class
对象。可以通过给对象引用提供的getClass()
方法获取
Student student = new Student();
Class class = student,getClass();
方法3:如果知道一个类class
的完整类名,可以通过Class
类的静态方法Class.forName()
获取
Class class = Class.forName("com.反射.Student");
方法4:对于基本数据类型(int、char、float等),通过基本数据类型的class获取
Class integerClass = int.class;
Class characterClass = char.class;
Class floatClass = float.class;
System.out.println(integerClass); // int
方法五:对于基本数据类型对应的包装类,可以通过类中的静态变量TYPE
获取到Class
类对象
Class type1 = Integer.TYPE;
Class type2 = Character.TYPE;
System.out.println(type1);// int
- 因为
Class
类对象在JVM中是唯一的,所以上述方法中获取到的CLass
类对象是同一个对象,可以用==
比较两个类对象
Java类动态加载
反射机制是Java实现动态语言的关键,也就是通过反射实现类的动态加载
- 静态加载:编译时就加载的类,如果程序中不存在该类则编译报错,依赖性太强
- 动态加载:运行时加载相关的类,如果运行时未使用到该类,即使程序中不存在该类,也不会编译错误,依赖性较弱
- 动态加载类
class
的特性对于 Java 程序非常重要。利用 JVM 动态加载class
的特性,我们才能在运行期根据条件去加载不同的实现类。
访问字段
Field getField(name)
:根据字段名获取某个 public 的 field(包括父类)Field getDeclaredField(name)
:根据字段名获取当前类的某个 field(不包括父类)Field[] getFields()
:获取所有 public 的 field(包括父类)Field[] getDeclaredFields()
:获取当前类的所有 field(不包括父类)
// 获取全部的全局变量类信息,并且打印Field[] field = class1.getDeclaredFields();System.out.println(Arrays.toString(field));// 获取public修饰的全局变量,并且打印Field[] field1 = class1.getFields();System.out.println(Arrays.toString(field1));System.out.println("--------------------------------");Field nameField = class1.getDeclaredField("name");System.out.println(nameField);Field heightField = class1.getDeclaredField("height");System.out.println(heightField);Field ageField = class1.getDeclaredField("age");System.out.println(ageField);System.out.println("---------------------------------");// 会报错,无法获取不被publi修饰符修饰变量的类信息Field nameField1 = class1.getField("name");System.out.println(nameField1);Field heightField1 = class1.getField("height");System.out.println(heightField1);Field agetField1 = class1.getField("age");System.out.println(agetField1);
调用方法
- Method getMethod(name, Class…):获取某个public的Method(包括父类)
- Method getDeclaredMethod(name, Class…):获取当前类的某个Method(不包括父类)
- Method[] getMethods():获取所有public的Method(包括父类)
- Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
// 获取方法信息Method[] declaredMethods = class1.getDeclaredMethods();System.out.println(Arrays.toString(declaredMethods));Method[] methods = class1.getMethods();System.out.println(Arrays.toString(methods));Method getAge = class1.getDeclaredMethod("getAge", int.class);Method aaa = class1.getDeclaredMethod("aaa", String.class, Integer.class);Method hh = class1.getDeclaredMethod("hh", String.class, int.class);Method run = class1.getDeclaredMethod("run");System.out.println(hh);System.out.println(aaa);System.out.println(run);System.out.println(getAge);Method run1 = class1.getMethod("run");System.out.println(run1);
调用构造方法
// 获取构造方法类信息 Constructor[] constructors = class1.getConstructors();System.out.println(Arrays.toString(constructors));Constructor[] declaredConstructors = class1.getDeclaredConstructors();System.out.println(declaredConstructors);Constructor declaredConstructor = class1.getDeclaredConstructor(String.class, Integer.class);System.out.println(declaredConstructor);Constructor declaredConstructor1 = class1.getDeclaredConstructor();System.out.println(declaredConstructor1);Constructor declaredConstructor2 = class1.getDeclaredConstructor(String.class, String.class, Double.class, Character.class, Integer.class);System.out.println(declaredConstructor2);