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