目录
一:概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
其实就是通过class文件对象去使用该文件中的成员变量,构造方法,成员方法
二:获取class文件对象
1:通过Object中的getClass()方法获取,返回该Object的运行时类
2:通过类名获取静态属性class
3: Class类中的静态方法(开发中最常用的方式)
public static 类<?> forName(String className) /返回与给定字符串名称的类或接口相关联的类对象。 //注意:这里需要写该类在本项目中完整路径中间用点连接
package day34;
public class Test1 {
public static void main(String[] args) {
Student student = new Student();
//通过getClass获取class对象
Class<? extends Student> aClass = student.getClass();
System.out.println(aClass);
//通过.class获取class对象
Class<Student> studentClass = Student.class;
System.out.println(studentClass);
try {
//通过Class.forName获取
Class<?> aClass1 = Class.forName("day34.Student");
System.out.println(aClass1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
三:获取class文件中的构造方法
1:public Constructor<?>[] getConstructors() //返回一个包含Constructor对象的数组, // 反映由此Constructor对象表示的类的所有公共类函数。 包括获取私有的,默认的修饰构造方法
2:public Constructor<?>[] getDeclaredConstructors() //返回反映Constructor对象表示的类声明的所有Constructor对象的数组类 。 //获取所有的构造方法,包括私有,该方法,打破了原先私有构造方法不能创建对象的隔阂
3:获取单个的构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes) //返回一个Constructor对象,该对象反映Constructor对象表示的类的指定的公共类函数。
public Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) //返回一个Constructor对象,该对象反映Constructor对象表示的类或接口的指定类函数
注意如果有参数要获取参数的class对象
4:根据构造方法创建对象
public T newInstance(Object... initargs) //对象表示的构造函数,使用指定的初始化参数创建和初始化构造函数的声明类的新实例。
package day34;
import java.lang.reflect.Constructor;
public class Test2 {
public static void main(String[] args) {
//获取Student的class对象
Class<Student> stu = Student.class;
//获取公共构造方法并输出
Constructor<?>[] constructors = stu.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("==================================");
//获取所有构造方法并输出
Constructor<?>[] declaredConstructors = stu.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println("==================================");
try {
//获取公共无参构造
Constructor<Student> constructor = stu.getConstructor();
System.out.println(constructor);
System.out.println("===============================");
//获取私有有参构造
Constructor<Student> declaredConstructor = stu.getDeclaredConstructor(String.class);
System.out.println(declaredConstructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
四:通过反射获取成员变量并使用
1:public Field[] getFields() 获取所有的成员变量 //返回包含一个数组Field对象反射由此表示的类或接口的所有可访问的公共字段类对象。 //获取该类中所有公共的成员变量
2:public Field[] getDeclaredFields() //返回的数组Field对象反映此表示的类或接口声明的所有字段类对象 //获取所有的成员变量,包括公共,受保护,默认(包)访问和私有字段
4:获取单个的成员变量
public Field getField(String name) 获取公共的成员变量
public Field getDeclaredField(String name) 获取公共的成员变量
void set(Object obj, Object value)
//将指定对象参数上的此 Field对象表示的字段设置为指定的新值。
如果没有权限访问可以用 setAccessible(true)来进行暴力访问
package day34;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Test3 {
public static void main(String[] args) throws Exception{
Class<?> stu = Class.forName("day34.Student");//获得学生class对象
Constructor<?> constructor = stu.getConstructor();//获得无参公共构造
Object o = constructor.newInstance();//根据无参构造创建学生对象
System.out.println(o);//输出对象
System.out.println("==========================");
//获得公共变量并输出
Field[] fields = stu.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("==========================");
//获得所有变量并输出
Field[] declaredFields = stu.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("==========================");
//获得单个变量并赋值,然后再次输出赋值后的对象
Field sex = stu.getField("sex");
sex.set(o, "男");
Field name = stu.getDeclaredField("name");
//当没有权限赋值时暴力访问.IllegalAccessException
name.setAccessible(true);
name.set(o, "小花");
System.out.println(name);
Field age = stu.getDeclaredField("age");
//当没有权限赋值时暴力访问.IllegalAccessException
age.setAccessible(true);
age.set(o, 18);
System.out.println(o);
}
}
五:通过反射获得成员方法并使用
1: public 方法[] getMethods() //返回包含一个数组方法对象反射由此表示的类或接口的所有公共方法类对象, // 包括那些由类或接口和那些从超类和超接口继承的声明。 //获取的是所有公共的方法,不光获取的是自己的公共方法,还包括父类的
2:public 方法[] getDeclaredMethods() //返回包含一个数组方法对象反射的类或接口的所有声明的方法,通过此表示类对象, // 包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。 //只能获取自己的所有方法,包括私有的
3:public 方法 getMethod(String name,类<?>... parameterTypes) //返回一个方法对象,它反映此表示的类或接口的指定公共成员方法类对象。 //注意:只写方法名,不写小括号
4:public 方法 getDeclaredMethod(String name,类<?>... parameterTypes)返回一个方法对象,包括公共,保护,默认(包)访问和私有方法
5:Object invoke(Object obj, Object... args) //在具有指定参数的 方法对象上调用此 方法对象表示的底层方法。
package day34;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Test4 {
public static void main(String[] args) throws Exception{
Class<?> aClass = Class.forName("day34.Student");//创建学生class对象
//获取所有的公共方法和父类的公共方法并输出
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("=============================");
//获取所有的方法包括私有的方法并输出
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("=============================");
//获得学生的无参构造然后根据无参构造创建对象
Constructor<?> constructor = aClass.getConstructor();
Object o = constructor.newInstance();
//获得单个方法并执行
Method show = aClass.getMethod("show");
show.invoke(o);
Method show1 = aClass.getDeclaredMethod("show", int.class);
show1.setAccessible(true);//暴力访问
Object invoke = show1.invoke(o,10);
Method study = aClass.getDeclaredMethod("study");
study.setAccessible(true);//暴力访问
study.invoke(o);
}
}
六:解释
1:所用的类是学生类(如下)
package day34;
public class Student {
private int age;
public String sex;
private String name;
public Student() {
}
private Student(String sex){
this.sex=sex;
}
public Student(int age, String sex) {
this.age = age;
this.sex = sex;
}
public void show(){
System.out.println("show");
}
private void show(int i){
System.out.println("show"+"**"+i);
}
private void study(){
System.out.println("study");
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", sex='" + sex + '\'' +
", name='" + name + '\'' +
'}';
}
}
2:关于抛异常
由于会有错误,如果正常做项目应该是try...catch,但是为了方法观看就直接在main方法上抛出了一个大的异常