反射允许对成员变量,成员方法和构造方法的信息进行编程访问
获取class对象的三种方式:
① Class.forName("全类名")
② 类名.class
③ 对象.getClass()
使用这三种方式的时机:
在源代码阶段,字节码文件还在硬盘中,未加载到内存,使用第一种方式;在加载阶段,使用第二种方;在运行阶段,使用第三种方式
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException {
//1.第一种方式
//全类名:包名 + 类名
//最为常用的
Class clazz1 = Class.forName("test1.Student");
//2.第二种方式
//一般更多的是当做参数进行传递
Class clazz2 = Student.class;
//3.第三种方式
//当我们已经有了这个类的对象时,才可以使用
Student s = new Student();
Class clazz3 = s.getClass();
}
}
利用反射获取构造方法:
Class类中用于获取构造方法的方法:
① Constructor<?>[] getConstructors()
:返回所有公共构造方法对象的数组
② Constructor<?>[] getDeclaredConstructors()
:返回所有构造方法对象的数组
③ Constructor<T> getConstructor(Class<?>... parameterTypes)
:返回单个公共构造方法对象
④ Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
:返回单个构造方法对象
Constructor类中用于创建对象的方法:
① T newInstance(Object... initargs)
:根据指定的构造方法创建对象
② setAccessible(boolean flag)
:设置为true,表示取消访问检查,可越过private权限来构造对象
public class Student {
private String name;
private int age;
public Student() {
}
private Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name) {
this.name = name;
}
protected Student(int age) {
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.获取class字节码文件对象
Class clazz = Class.forName("test2.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.getConstructor();
System.out.println(con1);
Constructor con2 = clazz.getDeclaredConstructor(int.class);
System.out.println(con2);
Constructor con3 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con3);
int modifiers = con3.getModifiers(); //不同权限修饰符以不同的整数表示
System.out.println(modifiers);
Parameter[] parameters = con3.getParameters(); //获取所有参数
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
//暴力反射:表示临时取消权限检验,使得即使是private的构造方法,也可以用来构造对象
con3.setAccessible(true);
Student stu = (Student) con3.newInstance("张三", 23);
System.out.println(stu);
}
}
反射获取成员变量:
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 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;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return gender
*/
public String getGender() {
return gender;
}
/**
* 设置
* @param gender
*/
public void setGender(String gender) {
this.gender = gender;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
}
}
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
//1.获取class字节码文件的对象
Class<?> clazz = Class.forName("test3.Student");
//2.获取所有的成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//获取单个的成员变量
Field name = clazz.getDeclaredField("name");
System.out.println(name);
//获取权限修饰符
int modifiers = name.getModifiers();
System.out.println(modifiers);
//获取成员变量的名字
String n = name.getName();
System.out.println(n);
//获取成员变量的数据类型
Class<?> type = name.getType();
System.out.println(type);
//获取成员变量记录的值
Student s = new Student("zhangsan", 23, "男");
name.setAccessible(true); //这里需要临时取消权限检验,因为name是private的
String value = (String) name.get(s);
System.out.println(value);
//修改对象里面记录的值
name.set(s, "zhanghaisen");
System.out.println(s);
}
}
利用反射获取成员方法:
Class类中用于获取成员方法的方法:
① Method[] getMethods()
:返回所有公共成员方法对象的数组,包括继承的
② Method[] getDeclaredMethods()
:返回所有成员方法对象的数组,不包括继承的
③ Method getMethod(String name, Class<?>... parameterTypes)
:返回单个公共成员方法对象
④ Method getDeclaredMethod(String name, Class<?>... parameterTypes)
:返回单个成员方法对象
Method类中用于创建对象的方法:
Object invoke(Object obj, Object... args)
:运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
public void sleep() {
System.out.println("睡觉");
}
private String eat(String sth) throws IOException, NullPointerException {
System.out.println("在吃" + sth);
return "好吃";
}
private void eat(String sth, int a) {
System.out.println("在吃" + sth);
}
}
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//1.获取class字节码文件对象
Class clazz = Class.forName("test4.Student");
//2.获取里面所有的方法对象(包括在父类中所有的公共方法)
/*Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}*/
//获取里面所有的方法(不能获取父类的,但是可以获取本类中私有的方法)
/*Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}*/
//获取指定的单一方法
Method m = clazz.getDeclaredMethod("eat", String.class);
System.out.println(m);
//获取方法的修饰符
int modifiers = m.getModifiers();
System.out.println(modifiers);
//获取方法的名字
String name = m.getName();
System.out.println(name);
//获取方法的形参
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
//获取方法抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
//方法运行
Student s = new Student();
m.setAccessible(true);
String res = (String) m.invoke(s, "汉堡包");
System.out.println(res);
}
}
反射的作用:
① 获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
② 结合配置文件,动态地创建对象并调用方法
练习:
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
public class Teacher {
private String name;
private int age;
private double height;
private String gender;
public Teacher() {
}
public Teacher(String name, int age, double height, String gender) {
this.name = name;
this.age = age;
this.height = height;
this.gender = gender;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return height
*/
public double getHeight() {
return height;
}
/**
* 设置
* @param height
*/
public void setHeight(double height) {
this.height = height;
}
/**
* 获取
* @return gender
*/
public String getGender() {
return gender;
}
/**
* 设置
* @param gender
*/
public void setGender(String gender) {
this.gender = gender;
}
public String toString() {
return "Teacher{name = " + name + ", age = " + age + ", height = " + height + ", gender = " + gender + "}";
}
}
public class Test5 {
public static void main(String[] args) throws IOException, IllegalAccessException {
Student s = new Student("张三", 18);
Teacher t = new Teacher("zhs", 19, 177.5, "男");
//saveObject(s)
saveObject(t);
}
public static void saveObject(Object obj) throws IllegalAccessException, IOException {
Class clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
BufferedWriter bw = new BufferedWriter(new FileWriter("day32-code\\src\\test5\\a.txt"));
for (Field field : fields) {
field.setAccessible(true);
//获取字段名字
String name = field.getName();
//获取字段值
Object value = field.get(obj);
bw.write(name + "=" + value);
bw.newLine();
}
bw.close();
}
}
动态创建对象,即创建配置文件内容里的对象,并调用内容里的方法,而即使配置文件发生改变,程序也不用改变
配置文件:
classname=test6.Teacher
method=teach
public class Teacher {
private String name;
private double salary;
public Teacher() {
}
public Teacher(String name, double salary) {
this.name = name;
this.salary = salary;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return salary
*/
public double getSalary() {
return salary;
}
/**
* 设置
* @param salary
*/
public void setSalary(double salary) {
this.salary = salary;
}
public String toString() {
return "Teacher{name = " + name + ", salary = " + salary + "}";
}
public void teach() {
System.out.println("老师在教书");
}
}
public class Test6 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.读取配置文件中的信息
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("day32-code\\src\\test6\\prop.properties");
prop.load(fis);
fis.close();
//2.获取全类名和方法名
String className = (String) prop.get("classname");
String methodName = (String) prop.get("method");
//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);
}
}