认识反射
反射机制
Java的反射机制是Java的特性之一,反射机制是构建框架技术的基础所在。
Java反射机制是指在运行状态中,动态获取信息以及冬天调用对象方法的功能。
Java反射有3个动态性质:
(1)运行时生成对象实例。
(2)运行期间调用方法。
(3)运行时更改属性。
通过Java反射,可以实现以下功能:
(1)在运行时判断任意一个对象所属的类。
(2)在运行时构造任意一个类的对象。
(3)在运行时判断任意一个类所具有的方法和属性。
(4)在运行时调用任意一个对象的方法。
Java反射常用API
使用Java反射技术常用的类如下:
(1)Class类:反射的核心类,反射所有的操作都是围绕该类来生成的,通过Class类,可以获取类的属性、方法等内容信息。
(2)Field类:表示类的属性,可以获取和设置类中属性的值。
(3)Method类:表示类的方法,可以用来获取类中方法的信息,或者执行方法。
(4)Constructor类:表示类的构造方法。
在Java程序中使用反射的基本步骤如下:
(1)导入java.lang.reflect.*。
(2)获得需要操作的类的java.lang.Class对象
(3)调用Class的方法获取Field、Method等对象。
(4)使用反射API进行操作。
反射的应用
获取类的信息
通过反射获取类的信息分为两步,首先获取Class对象,然后通过Class对象获取信息。
获取Class对象
每个类被加载后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问Java虚拟机加中的这个类。Java程序中获得Class对象通常有如下3中方式:
(1)调用对象的getClass()方法
getClass()方法是java.lang.Object类中的一个方法,所有的Java对象都可以调用该方法,该方法会返回该对象所属类对应的Class对象。使用方式如以下代码所示:
Student p=new Student()://Student为自定义的学生类型
Class cla=p.getClass();//cla为class对象
(2)调用类的class属性
调用某个类的class属性可获取该类对应的Class对象,这种方式需要在编译期期间就知道类的名称。使用的方式如以下代码所示:
Class cla=Student.class;//Student为自定义的学生类型
上述代码中,Student.class将会返回Student类对应的Class对象。
(3)使用Class类的forName()静态方法
使用Class类的forName()静态方法也可以获取该类对应的Class对象。该方法需要传入字符串参数,该字符串参数的值是某个类的全名,既要在类名前添加完整的包名。
Class cla=Class.forName("com.pb.jadv.reflection.Student");//正确
Class cla=Class.forName("Student")//错误
在上述代码中,如果传入的字符串不是类的全名,就会抛出一个ClassNotFoundException异常。
从Class对象获取信息
在获得了某个类所对应的Class对象之后,程序就可以调用Class对象的方法来获取该类的详细信息。Class类提供了大量实例方法来获取Class对象所对应类的详细信息。
(1)访问Class对应的类所包含的构造方法
访问Class对应的类所包含的构造方法的常用方法如下所示:
方法 | 说明 |
---|---|
Constructor getConstructor(Class[] params) | 返回此Class对象所包含的类的指定的public构造方法,params参数是按声明顺序指定该方法参数类型的Class对象的一个数组。构造方法的参数类型与params所指定的参数类型匹配 |
Constructor[] getConstructors() | 返回此Class对象所包含的类的所有public构造方法 |
Constructor getDeclaredConstructor(Class[] params) | 返回此Class对象所包含的类的指定构造方法,与构造方法的访问级别无关 |
Constructor[] getDeclaredConstructort() | 返回此Class对象所包含的类的所有构造方法,与构造方法的访问级别无关 |
(2)访问Class对应的类所包含的方法
访问Class对应的类所包含的方法的常用方法如下所示:
方法 | 说明 |
---|---|
Method getMethod(String name,Class[] params) | 返回此Class对象所包含的类的指定的public方法,name参数用于指定方法名称,params参数时按声明顺序标志该方法参数类型的Class对象的一个数组 |
Method[] getMethod() | 返回此Class对象所包含的类的所有public方法 |
Method getDeclaredMethod(String name,Class[]params) | 返回此Class对象所包含的类的指定方法,与方法的访问级别无关 |
Method[] getDeclaredMethod() | 返回此Class对象所包含的类的全部方法,与方法的访问级别无关 |
(3)访问Class对应的类所包含的属性
访问Class对应的类所包含的属性的常用方法如下所示:
方法 | 说明 |
---|---|
Field getField(String name) | 返回此Class对象所包含的类的指定的public属性,name参数用于指定属性名称 |
Field[] getFields() | 返回此Class对象所包含的类的所有public属性 |
Field getDeclareField(String name) | 回此Class对象所包含的类的指定属性,与属性的访问级别无关,name表示属性名称 |
Field getDeclareFields() | 回此Class对象所包含的类的全部属性,与属性的访问级别无关 |
Class对象可以获得该类里的成员、包括方法、构造方法及属性。其中方法由Method对象表示,构造方法由Constructor对象表示,属性由Field表示。
Method、Constructor、Field这3个类都定义值java.lang.reflect包下,并实现了java.lang.reflect.Member接口,程序可以通过Method对象来执行对应的方法,通过Constructor对象来调用相应的构造方法创建对象,通过Field对象直接访问并修改对象的属性值。
创建对象
通过反射来创建对象有如下两种方式:
(1)使用Class对象的newInstance()方法创建对象
(2)使用Constructor对象创建对象。
使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造方法,而执行newInstance()方法时实际上是利用默认构造方法来创建该类的实例。而使用Constructor对象创建对象,要先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法创建该Class对象对应类的实例。通过这种方式可以选择使用某个类的指定构造方法来创建实例。
如果创建Java对象时不是利用默认构造方法,而是使用指定的构造方法,则可以利用Constructor对象,每个Constructor对应一个构造方法。指定构造方法创建Java对象需要如下3个步骤:
(1)获取该类的Class对象。
(2)利用Class对象的getConstructor()方法来获取指定构造方法。
(3)调用Constructor的newInstance()方法创建Java对象。
访问类的属性
使用Field对象可以获取对象的属性。通过Field对象可以对属性进行取值或赋值操作。
最主要的方法:
setAccessible(true)//对获取到的属性设置访问权限。参数为true,可以对私有属性取值和赋值。
访问类的方法
使用Method对象可以调用对象的方法。在Method类中包含一个invoke()方法,方法定义如下:
Objecet invoke(Object obj,Object args)
其中obj是执行该方法的对象,args是执行该方法时传入该方法的参数。
示例一:
import java.lang.reflect.Constructor;
public class TestConstructor {
public static void main(String[] args) throws Exception{
Class<Student> c = Student.class;
Constructor<Student> sClass =
c.getDeclaredConstructor(int.class,
String.class, String.class);
sClass.setAccessible(true);
Student s = sClass.newInstance(2, "马爸爸", "爹");
System.out.println(s);
}
}
输出结果:
示例二:
import java.lang.reflect.Method;
public class TestMethod {
public static void main(String[] args)throws Exception {
Student s = TestStudent.getStudent();//构造对象
Class<Student> c = Student.class;
Method setStuId = c.getDeclaredMethod("setStuId", int.class);//获取方法
setStuId.setAccessible(true);//权限
setStuId.invoke(s, 3);//指定对象传入参数
Method getStudId = c.getDeclaredMethod("getStuId");
getStudId.setAccessible(true);
Object stuId = getStudId.invoke(s);
System.out.println(s);
System.out.println(stuId);
}
}
输出结果:
示例三:
import java.lang.reflect.Field;//获取属性
public class TestField {
public static void main(String[] args) throws Exception{
Student s = TestStudent.getStudent();
Class<Student> c = Student.class;
Field stuId = c.getField("stuId");
stuId.set(s, 11);
Field stuName = c.getDeclaredField("stuName");
stuName.setAccessible(true);
stuName.set(s,"泡腾片");
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
System.out.println(field.get(s));
}
System.out.println(s);
}
}
输出结果:
示例四:
public class Student {
public int stuId;
private String stuName;
String gender;
private Student(){
}
public Student(int stuId, String stuName, String gender) {
this.stuId = stuId;
this.stuName = stuName;
this.gender = gender;
}
private int getStuId() {
return stuId;
}
private void setStuId(int stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public String getGender() {
return gender;
}
@Override
public String toString() {
return "Student{" +
"stuId=" + stuId +
", stuName='" + stuName + '\'' +
", gender='" + gender + '\'' +
'}';
}
public void setGender(String gender) {
this.gender = gender;
}
}
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class TestStudent<T> {
public static void main(String[] args) throws Exception {
TestStudent s = new TestStudent();
// //获取类对象的另一种方法
// //① Class<? extends TestStudent> sC = s.getClass();
// //1、获取类对象
// Class<Student> stu=Student.class;
// //② Class ss = Class.forName("cn.kgc.kb09.Student");
// //2、通过对象获取构造方法
// Constructor<Student> constructor = stu.getDeclaredConstructor();
// constructor.setAccessible(true);
// //3、通过构造方法创建对象
// Student student = constructor.newInstance();
//Student student =getStudent();
TestStudent ts = new TestStudent();
Student student=(Student) ts.getObject(Student.class);
// student.stuId = 1;
// student.gender = "男";
// student.setStuName("王思聪");
System.out.println(student);
}
//public T getObject(String classPath){
public T getObject(Class<T> tClass){
T t=null;
try {
// Class<T> tClass = (Class<T>) Class.forName(classPath);
Constructor<T> c = tClass.getDeclaredConstructor();
c.setAccessible(true);
t = c.newInstance();
// } catch (ClassNotFoundException e) {
// e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return t;
}
public static Student getStudent(){
Class<Student> s = Student.class;
Student stu=null;
try {
Constructor<Student> c = s.getDeclaredConstructor();
c.setAccessible(true);
stu = c.newInstance();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}return stu;
}
}
输出结果: