目录
一、什么是反射?
- 反射允许对成员变量,成员方法和构造方法的信息进行编程访问。
-
反射就是把java类中的各种成分映射成一个个的Java对象
-
例如:一个类有:成员变量、方法、构造方法等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
idea自动提示 |
|
提问:为什么不能用IO流从上往下一行一行的进行读取呢?
- 但是当我们读取到构造方法和普通成员方法时,无法区分。
- 成员变量和局部变量也很难区分。
因此我们使用 反射 获取成员变量就可以得到成员所有信息:
反射的作用:
- 获取一个类里面的所有的信息,获取到了之后,再执行其他的业务逻辑。
- 结合配置文件,动态的创建对象并调用方法。
二、获取 Class对象 的三种方式
使用反射的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)
- Class.forName ( " 全类名 " ) ; (最为常用)
- 类名 . class (一般更多的是当做参数进行传递)
- 对象 . getClass ( ) ; (当已经有类对象是才能使用)
public class MyReFlectDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 1.第一种方式
// 全类名 : 包名 + 类名
Class clazz1 = Class.forName("ReFlect.Student");
System.out.println(clazz1); // class ReFlect.Student
// 2.第二种方式
Class clazz2 = Student.class;
System.out.println(clazz2); // class ReFlect.Student
System.out.println(clazz1 == clazz2); // true
// 3.第三种方式
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz1 == clazz2); // true
System.out.println(clazz2 == clazz3); // true
}
}
三、反射获取构造方法(Constructor)
Class类中获取构造方法的方法:
Constructor <?> [ ] getConstructors() | 返回所有公共构造方法对象的数组 |
Constructor <?> [ ] getDeclaredConstructors() | 返回所有构造方法对象的数组 |
Constructor <T> getConstructor ( Class <> .. parameterTypes ) | 返回单个公共构造方法对象 |
Constructor <T> getDeclaredConstructor(Class <>.. parameterTypes) | 返回单个构造方法对象 |
Constructor类中用于创建对象的方法:
T newInstance ( Oject... initargs ) | 根据指定的构造方法创建对象 |
setAccessible ( boolean flag ) | 设置为true,表示取消访问检查 |
public class MyReFlectDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException, SecurityException {
// 1.获取Class字节码文件的对象
Class clazz = Class.forName("ReFlect.Student");
// 2.获取构造方法
// 获取所有
Constructor[] cons1 = clazz.getConstructors();
for (Constructor con : cons1) {
System.out.println(con);
}
Constructor[] cons2 = clazz.getDeclaredConstructors();
for (Constructor con : cons2) {
System.out.println(con);
}
// 获取单个
Constructor con1 = clazz.getDeclaredConstructor();
System.out.println(con1); //public ReFlect.Student()
Constructor con2 = clazz.getDeclaredConstructor(String.class);
System.out.println(con2); //public ReFlect.Student(java.lang.String)
Constructor con3 = clazz.getDeclaredConstructor(int.class);
System.out.println(con3); //public ReFlect.Student(int)
//获取两个参数
Constructor con4 =
clazz.getDeclaredConstructor(String.class,int.class);
System.out.println(con4); //public
ReFlect.Student(java.lang.String,int)
//接下来我们就可以反射获取所有信息:
//比如1:权限修饰符
int modifiers = con4.getModifiers();
System.out.println(modifiers); //1
//比如2:获取构造方法所有参数
Parameter[] parameters = con4.getParameters();
for(Parameter parameter:parameters) {
System.out.println(parameter);
//java.lang.String arg0
//int arg1
}
//比如3:利用构造方法创建对象
con4.setAccessible(true); //暴力反射:表示临时取消权限校验
Object stu = (Student)con4.newInstance("张三",23);
System.out.println(stu); //Student [name=张三, age=23]
}
}
//Student.java
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name) {
this.name = name;
}
public Student(int age) {
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;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
四、反射获取成员变量(Field)
Class类中获取成员变量的方法:
Field [ ] getFields() | 返回所有公共成员变量对象的数组 |
Field [ ] getDeclaredFields ( ) | 返回所有成员变量对象的数组 |
Field getField ( String name ) | 返回单个公共成员变量对象 |
Field getDeclaredField ( String name ) | 返回单个成员变量对象 |
Field类中用于创建对象的方法:
void set ( Object obj , Object value ) | 赋值 |
Object get ( Object obj ) | 获取值 |
public class MyReFlectDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchFieldException{
// 1.获取Class字节码文件的对象
Class clazz = Class.forName("ReFlect.Student");
// 获取成员变量
//获取所有的成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
//private java.lang.String ReFlect.Student.name
//private int ReFlect.Student.age
//public java.lang.String ReFlect.Student.gender
}
//获取单个成员变量
Field gender = clazz.getField("gender");
System.out.println(gender);
//public java.lang.String ReFlect.Student.gender
//Field name = clazz.getField("name");
//无法获取 name是private私有的
Field name = clazz.getDeclaredField("name");
System.out.println(name);
//private java.lang.String ReFlect.Student.name
//获取到成员变量后我们可以继续:
//1.获取权限修饰符
int modifier = name.getModifiers();
System.out.println(modifier); //2
//2.获取成员变量名
String n = name.getName();
System.out.println(n); //name
//3.获取数据类型
Class<?> type = name.getType();
System.out.println(type); //class java.lang.String
//4.获取成员变量记录的值
Student s = new Student("张三",23,"男");
name.setAccessible(true);
Object value = (String)name.get(s); //张三
System.out.println(value);
//5.修改成员变量记录的值
name.set(s, "李四");
System.out.println(s); //Student [name=李四, age=23, gender=男]
}
}
public class Student {
private String name;
private int age;
public String gender;
public Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
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;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
}
五、反射获取成员方法(Method)
Class类中获取成员方法的方法:
Method [ ] getMethods ( ) | 返回所有公共成员方法对象的数组,包括继承的 |
Method [ ] getDeclaredMethods ( ) | 返回所有成员方法对象的数组,不包括继承的 |
Method getMethod ( String name , Cass <?> .. parameterTypes ) | 返回单个公共成员方法对象 |
Method getDeclaredMethod ( String name , Class<?>... parameterTypes ) | 返回单个成员方法对象 |
Method类中用于创建对象的方法:
Object invoke ( Object obj , Object... args ) | 运行方法 |
参数一:用obj对象调用该方法 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
public class MyReFlectDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchFieldException {
// 1.获取Class字节码文件的对象
Class clazz = Class.forName("ReFlect.Student");
// 2.获取里面所有的方法对象
//(包含所有父类中的所有的公共方法)
Method[] methods1 = clazz.getMethods();
for(Method method : methods1) {
System.out.println(method);
}
//获取里面所有的方法对象(只能获取本类中私有方法)
Method[] methods2 = clazz.getDeclaredMethods();
for(Method method : methods2) {
System.out.println(method);
}
//3.获取指定单一方法对象
Method m = clazz.getDeclaredMethod("eat", String.class);
System.out.println(m); //private void ReFlect.Student.eat(java.lang.String)
//1.获取权限修饰符
int modifers = m.getModifiers();
System.out.println(modifers); //2
//2.获取方法名
String name = m.getName();
System.out.println(name); //eat
//3.获取方法形参
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter); //java.lang.String arg0
}
//4.获取方法返回值
//5.获取方法抛出异常
Class<?>[] exceptionTypes = m.getExceptionTypes();
for(Class exceptiontype : exceptionTypes) {
System.out.println(exceptiontype);
//class Java.io.TOException
//class java. lang. NullPointerException
//class java. lang.ClassCastException
}
//方法运行
Student s = new Student();
m.setAccessible(true);
m.invoke(s, "汉堡包");
}
}
public class Student {
private String name;
private int age;
public Student() {
}
public Student(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;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
public void sleep() throws
IOException, NullPointerException, ClassCastException {
System.out.println("睡觉");
}
private void eat(String something) {
System.out.println("在吃" + something);
}
}
六、综合练习
1. 保存信息
对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去。
public class MyReFlectDemo {
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, IOException {
Student s = new Student("张三", 23, '男', 175, "睡觉");
Teacher t = new Teacher("李四", 10000);
saveObject(s);
}
// 把对象里面所有的成员变量名和值保存到本地文件中
public static void saveObject(Object obj) throws IllegalArgumentException, IllegalAccessException, IOException {
// 1.获取字节码文件的对象
Class clazz = obj.getClass();
// 创建IO流
BufferedWriter bw = new BufferedWriter(new FileWriter("java02//a.txt"));
// 2.获取所有的成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
// 获取成员变量的名字
String name = field.getName();
// 获取成员变量的值
Object value = field.get(obj);
// 写出数据
bw.write(name + "=" + value);
bw.newLine();
// System.out.println(name + "=" +value);
}
bw.close();
}
}
2. 配置文件结合创建对象
结合配置文件,动态的创建对象,并调用方法
public class MyReFlectDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//1.读取配置文件中的信息
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("java02//prop.properties");
prop.load(fis);
fis.close();
System.out.println(prop);
//2.获取全类名和方法名
String classname = (String)prop.get("classname");
String methodname = (String)prop.get("method");
System.out.println(classname);
System.out.println(methodname);
//3.利用反射创建对象并运行方法
Class clazz = Class.forName(classname);
//获取构造方法
Constructor con = clazz.getDeclaredConstructor();
Object o = con.newInstance();
System.out.println(o);
//获取成员方法并运行
Method method = clazz.getDeclaredMethod(methodname);
method.setAccessible(true);
method.invoke(o);
}
}