本文根据黑马课程总结总结而成。
反射机制的理解
Reflection允许以编程方式访问有关已加载类的字段,方法和构造函数的信息,以及使用反射字段,方法和构造函数在封装和安全限制内对其底层对应项进行操作。
简单地解释:反射就是加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。
- 反射第一步:加载类,获取类的字节码:Class对象
- 获取类的构造器:Constructor对象
- 获取类的成员变量:Field对象
- 获取类的成员方法:Method对象
第一步:加载类,获取Class对象
-
Class c1 = 类名.class
-
调用Class提供方法:public static Class forName(String package);
-
Object提供的方法:public Class getClass(); Class c3 = 对象.getClass();
// 第一种 Class c1 = Student.class; System.out.println(c1.getName()); // 第二种 Class c2 = Class.forName("org.example.reflect.Student"); // 第三种 Student s = new Student(); Class c3 = s.getClass();
第二步:获取类的构造器
-
Constructor<?>[] getConstructors() // 获取全部构造器(只能获取public修饰的)
-
Constructor<?>[] getDeclaredConstructors() // 获取全部构造器(只要存在就能拿到)
-
Constructor<?>[] getConstructor(Class<?> … parameterTypes) // 获取某个构造器(只能获取public修饰的)
-
Constructor<?>[] getDeclaredConstructor(Class<?> … parameterTypes) // 获取某个构造器(只要存在就能拿到)
// Cat.java class Cat{ private String name; private int age; public Cat(){ } public Cat(String name, int age){ this.name = name; this.age = age; } public void run(){ System.out.println("猫跑的很快!"); } public String eat(String name){ return "猫在吃" + name; } 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; } } // TestConstructor.java public void testGetConstructors(){ // 1.反射第一步:必须先得到这个类的Class对象 Class c = Cat.class; // 2.获取类的全部构造器(只能是public方法) Constructor[] constructors = c.getConstructors(); // 2.获取类的全部构造器,无论什么方法进行修饰 Constructor[] constructors = c.getDeclaredConstructors(); // 3.遍历数组中每个构造器对象 for(Constructor constructor: constructors){ System.out.println(constructor.getName() + "----->" + constructor.getParameterCount()); } } public void testGetConstructor() throws Exception{ Class c = Cat.class; // 获取单个无参构造器(只能是public修饰的) Constructor constructor = c.getConstructor(); // 获取单个无参构造器(什么修饰的都可以) Constructor constructor = c.getDeclaredConstructor(); // 获取有参构造器 Constructor constructor2 = c.getConstructor(String.class, int.class); // 获取有参构造器 Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class); }
获取类构造器的作用:初始化对象返回
Class c = Cat.class; Constructor constructor1 = c.getDeclaredConstructor(); Cat cat = (Cat) constructor1.newInstance(); // 由于getDeclaredConstructor()可以获取private修饰的构造器,而private构造器是不允许外界访问的,所以会出现IllegalAccessException。 // 可以这样修改 constructor1.setAccessible(true); // 禁止检查访问权限 Cat cat = (Cat) constructor1.newInstance(); // 调用有参数构造器初始化对象 Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class); constructor2.setAccessible(true); Cat cat2 = (Cat) constructor2.newInstance("hhh", 3);
第三步:获取类的成员变量
-
public Field[] getFields() // 只能获取public修饰的
-
public Field[] getDeclaredFields() // 无论什么修饰,都可以获取到
-
public Field getField(String name) // 获取某个public修饰的成员变量
-
public Field getDeclaredField(String name) // 无论什么修饰,都可以获取到
// 获取类的全部成员变量 Field[] fields = c.getDeclaredFields(); // 定义某个成员变量 Field fName = c.getDeclaredField("name"); System.out.println(fName.getName() + "--->" + fName.getType());
获取类的成员变量作用:赋值和取值
// 赋值 Cat cat = new Cat(); fName.setAccessible(true); // 因为name使用的是private修饰的,所以必须设置禁止查看访问权限 fName.set(cat, "图图"); // 取值 String name = (String) fName.get(cat);
第四步:获取类的Method方法
-
Method[] getMethods // 获取全部方法(只能是pubic修饰的)
-
Method[] getDeclaredMethods // 同上,但是只要存在就能拿到
-
Method getMethod(String name, Class<?> … parameterTypes) // 获取某个成员方法,只能是public修饰的
-
Method getDeclaredMethod(String name, Class<?> … parameterTypes) // 获取某个成员方法,只要存在就能拿到
Class c = Cat.class; Method[] method = c.getDeclaredMethods(); for(Method method: methods){ System.out.println(method.getName() + "---->" + method.getParameterCount() + "---->" + method.getReturnType()); } // 获取某个方法对象 Method run = c.getDeclaredMethod("run"); // 没有参数 Method eat = c.getDeclaredMethod("eat", String.class);
获取成员方法的作用:执行成员方法
// 执行成员方法 // public Object invoke(Object obj, Object … args) // public void setAccessible(boolean flag) Cat cat = new Cat(); run.setccessible(true); // 如果run方法是私有的,需要加上该语句 Object rs = run.invoke(cat); // 用cat对象调用无参的构造方法 run.setccessible(true); // 如果eat方法是私有的,需要加上该语句 String rs2 = (String) eat.invoke(cat, "fish");
反射作用
- 基本作用:可以得到一个类得全部成分然后对其进行操作;
- 可以破坏封装性:可以访问私有构造器
- 最重要的用途:适合做java的框架,基本上,主流的框架都会基于反射设计出一些通用的功能模块