反射的概述
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。
获取Class对象的三种方式
1.Object ——> getClass();
2.任何数据类型(包括基本数据类型)都有一个“静态”的class属性
3. 通过Class类的静态方法:forName(String className)(常用)
//方式一:通过类名.class
Class class1=String.class;
//方式二:对象.getClass()
String str=new String();
Class class2=str.getClass();
//方式三:Class的静态方法forName()
Class class3=Class.forName("java.lang.String");
三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。
Class对象的基本使用
要进行反射操作必须要拿到这个类对应的Class对象。要用某个类的无参构造方法创建该对象时,可以省略创建Constructor类对象的过程(java运行环境的缓存中保存了类的无参构造方法所对应的Constructor对象),以我们自定义的Student对象为例:
public class Student {
public String name;
public int age;
private String id;
String school;
public Student() {
}
private Student(String name) {
this.name=name;
}
public Student(String name, int age, String id, String school) {
this.name = name;
this.age = age;
this.id = id;
this.school = school;
}
private void play(){
System.out.println("游戏中+++++");
}
public void study() {
System.out.println("正在学习+++++");
}
public void eat() {
System.out.println("正在吃饭+++++");
}
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 String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", id=" + id + ", school=" + school + "]";
}
}
我们可以直接使用class对象的newInstance方法通过无参构造方法来创建对象
//获取Date的Class对象
Class cla=Class.forName("demo.Student");
//通过反射创建实例
Student student=(Student) cla.newInstance();
1.获取Constructor对象
一个类中往往会有多个构造方法,如果我们要调用有参构造来利用反射来创建实例对象,我们可以使用Class对象的Constructor数组,通过遍历数组来查看Student的所有公开的构造方法。
//获取Student的Class对象
Class cla=Class.forName("demo06.Student");
//调用Class对象的getConstructors方法获取到Constructor[]
Constructor[] constructors=cla.getConstructors();
//遍历构造器数组对象,查看Student对象拥有的public构造方法
for(Constructor constructor:constructors) {
//打印constructor
System.out.println(constructor);
}
我们可以看到,在Student中,还有一个private修饰的构造方法,我们可以使用Class对象的getDeclaredConstructors来获取所有定义的构造方法。
//获取Student的Class对象
Class cla=Class.forName("demo06.Student");
//调用Class对象的getConstructors方法获取到Constructor[]
Constructor[] constructors=cla.getDeclaredConstructors();
//遍历构造器数组对象,查看Student对象所有定义的构造方法
for(Constructor constructor:constructors) {
//打印constructor
System.out.println(constructor);
}
获取到所有的构造方法后,我们便可以选用自己所需要的构造方法来获取实例对象
//获取Student的Class对象
Class cla=Class.forName("demo06.Student");
//根据传入参数类型获取到指定构造器
//cla.getConstructor()为获取到指定的public的构造器
//cla.getDeclaredConstructor()为获取到指定的定义构造器
Constructor constructor=cla.getDeclaredConstructor(String.class);
//判断构造器是否为受保护的
if(!constructor.isAccessible()) {
//设置构造器为可访问的
constructor.setAccessible(true);
}
//调用constructor.newInstance()传入参数生成Student对象
Student student=(Student) constructor.newInstance("张三");
//打印对象
System.out.println(student);
代码的输出结果为:Student [name=张三, age=0, id=null, school=null]
由此可知我们成功地调用了受保护的构造方法创建了Student对象。
2.Field
Field类用来表示类中的字段:
Class.getFields()得到Class对象的所有字段返回的是Field数组
Class.getField(String name)返回一个Field对象Field对象对应的是某一个类的属性
要想得到某一个对象对应的属性值,需要用get(Object object)方法
对于非公有属性,只能通过Class的getDeclaredField(String fieldName)方法的到
对于私有属性要得到它所关联的对象的值
需要通过Field的setAccessible(boolean boolean)方法设置
Field类的getType()方法用来得到字段所属的类型
//获取Student的Class对象
Class cla=Class.forName("demo06.Student");
//获取Studen类的所有定义属性
//cla.getFields()获取Student类的所有public属性
//cla.getName()获取指定名称的属性
Field[] fields=cla.getDeclaredFields();
//对获取到的Field数组进行遍历
for(Field field:fields) {
//获取属性名称
System.out.println("属性名:"+field.getName());
//获取属性类型
System.out.println("类型:"+field.getType());
}
3.Method
Method getMethod(String name,Class<?>…parameterTypes)
按名称得到某个特定的public方法(包括从父类或接口继承的方法)
Method[] getMethods()
得到public方法(包括从父类或接口继承的方法)
Method[] getDeclaredMethods()
得到所有的方法(不包括继承的方法)
Method getDeclaredMethod(String name,Class<?>…parameterTypes)
按名称得到某个特定的方法(不包括继承的方法)
得到某个方法的对应Method对象,可以对其执行的方法:
Invoke(Object object, Object…obj)
用来调用Method所表示的方法。第一个参数表示该方法作用于哪个对象。(若调用的为静态方法,invoke()方法中第一个参数用null表示)
//获取Student的Class对象
Class cla=Class.forName("demo06.Student");
//a.getDeclaredMethods()获取Student类的所有定方法
//cla.getMethods()获取Student类的所有public方法
//cla.getMethod(name, parameterTypes)根据名称和参数类型获取指定方法
Method[] methods=cla.getDeclaredMethods();
for(Method method:methods) {
//获取方法名
System.out.println("方法名:"+method.getName());
//返回值为arameter数值
System.out.println("参数:"+method.getParameters());
//获取方法返回值
System.out.println("返回值类型:" +method.getReturnType());
}