1 反射的概念
编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。
运行期是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。
Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
Java 反射机制在服务器程序和中间件程序中得到了广泛运用。在服务器端,往往需要根据客户的请求,动态调用某一个对象的特定方法。此外,在 ORM 中间件的实现中,运用 Java 反射机制可以读取任意一个 JavaBean 的所有属性,或者给这些属性赋值。
Java 反射机制主要提供了以下功能,这些功能都位于java.lang.reflect包。
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
-
1.1 反射机制的优缺点
优点:
能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
- 与 Java 动态编译相结合,可以实现无比强大的功能。
- 对于 Java 这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
缺点:
- 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
- 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。
2 反射的使用
class Person {private String name;private Integer age;private String sex;public String school;public Person() {System.out.println("这是一个无参构造函数");}private Person(String str) {System.out.println("这是一个私有有参构造函数,str=" + str);}public Person(String name, Integer age, String sex) {this.name = name;this.age = age;this.sex = sex;System.out.println("这是一个有参构造函数,name=" + name + " ,age=" + age + " sex=" + sex);}public void like() {System.out.println("i like animal");}public void work(String str) {System.out.println("i am a " + str);}private void play(Integer age, String str) {System.out.println("my age is " + age + " years old; " + "i like to play " + str);}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getSchool() {return school;}public void setSchool(String school) {this.school = school;}}
2.1 反射获取属性
public class ReflectTest {public static void main(String[] args) {try {System.out.println("--------------属性--------------");Class c = Class.forName("com.example.springdemo.com.reflectTest.Person");//反射获取公共属性Field f = c.getField("school");System.out.println("公共属性:" + f.get(c.newInstance()));//反射获取私有属性Field f2 = c.getDeclaredField("name");f2.setAccessible(true);System.out.println("私有属性:" + f2.get(c.newInstance()));} catch (ClassNotFoundException | NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}}}
2.2 反射获取构造函数
public class ReflectTest {public static void main(String[] args) {try {System.out.println("----------构造函数---------");Class c = Class.forName("com.example.springdemo.com.reflectTest.Person");//反射获取无参构造函数Constructor cons = c.getConstructor(null);cons.newInstance(null);//反射获取有参构造函数Constructor cons2 = c.getConstructor(String.class, Integer.class, String.class);cons2.newInstance("张三", 18, "男");//反射获取私有有参构造函数Constructor cons3 = c.getDeclaredConstructor(String.class);cons3.setAccessible(true);cons3.newInstance("私有有参构造函数");//反射获取所有有参构造函数Constructor[] cons4 = c.getDeclaredConstructors();Arrays.stream(cons4).forEach(i -> System.out.println("构造函数:" + i));} catch (ClassNotFoundException | NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}}}
2.3 反射获取方法
public class ReflectTest {public static void main(String[] args) {try {System.out.println("----------------方法------------------");Class c = Class.forName("com.example.springdemo.com.reflectTest.Person");Method m = c.getMethod("like", null);m.invoke(c.newInstance(), null);//反射获取有参方法Method m2 = c.getMethod("work", String.class);m2.invoke(c.newInstance(), "coder");//反射获取私有方法Method m3 = c.getDeclaredMethod("play", Integer.class, String.class);m3.setAccessible(true);m3.invoke(c.newInstance(), 18, "basketball");} catch (ClassNotFoundException | NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}}}
2.4 通过反射越过泛型检查
public static void invokeList() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {List<Integer> integerList = new ArrayList<>();integerList.add(123);integerList.getClass().getMethod("add", Object.class).invoke(integerList,"abc");for (int i=0;i<integerList.size();i++){System.out.println(integerList.get(i));}// integerList.stream().forEach(System.out::println);}
输出:
true
