【Java基础】反射相关面试题
1. 什么是Java反射机制
Java 中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;
并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方
法的功能成为 Java 语言的反射机制。
2. 反射的优缺点
优点:
- 提高了灵活性,可以在运行时动态操作类和对象。
- 支持框架开发,很多框架(如 Spring)大量使用反射来进行依赖注入和动态代理等操作。
缺点:
- 性能开销较大,反射操作通常比直接调用慢。
- 代码安全性降低,反射可以绕过访问修饰符(如 private),可能导致不安全操作。
- 代码可读性和维护性降低,反射代码通常较为复杂,不易理解和调试。
3. 反射的应用场合
-
框架开发: 许多框架(如Spring、Hibernate)广泛使用反射来扫描和处理注解、注入依赖、管理Bean的生命周期等。通过反射,框架可以动态地发现和使用应用程序的类和方法。
-
对象序列化和反序列化:在对象序列化(如Java的JAXB或Jackson)过程中,反射用于访问对象的字段和方法,以将对象转换为字节流或其他格式,或者从这些格式重建对象。
-
代码生成和动态代理:反射用于生成代理类和动态字节码。例如,Java中的
java.lang.reflect.Proxy
类可以在运行时创建接口的实现。 -
测试工具和框架: 许多测试框架(如JUnit)使用反射来发现和调用测试方法,注入测试数据等。
4. 反射常用API
- Class 类:反射的核心类,可以获取类的属性,方法、等信息以及new实例等等。
java.lang
包下的 - Field 类:Java.lang.reflec 包中的类,表示类的成员变量,可以用来获取和设置类之中的属性
值。java.lang.reflect.Field
- Method 类: Java.lang.reflec 包中的类,表示类的方法,它可以用来获取类中的方法信息或
者执行方法。java.lang.reflect.Method
- Constructor 类: Java.lang.reflec 包中的类,表示类的构造方法,可以获取不同参数,不同权限的构造方法、还可以new实例。
java.lang.reflect.Constructor
/*
Class类中用于获取构造方法的方法
Constructor<?>[] getConstructors() 返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组
Constructor<T> getConstructor(Class<?>... parameterTypes) 返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造方法对象
Constructor类中用于创建对象的方法
T newInstance(Object... initargs) 根据指定的构造方法创建对象
setAccessible(boolean flag) 设置为true,表示取消访问检查
*/
/**
* Class类中用于获取成员变量的方法
* Field[] getFields(): 返回所有公共成员变量对象的数组
* Field[] getDeclaredFields(): 返回所有成员变量对象的数组
* Field getField(String name): 返回单个公共成员变量对象
* Field getDeclaredField(String name):返回单个成员变量对象
*
* Field类中用于创建对象的方法
* void set(Object obj, Object value):赋值
* Object get(Object obj) 获取值
*/
/**
* 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对象调用该方法
* 参数二:调用方法的传递的参数(如果没有就不写)
* 返回值:方法的返回值(如果没有就不写)
*
* 获取方法的修饰符
* 获取方法的名字
* 获取方法的形参
* 获取方法的返回值
* 获取方法的抛出的异常
*/
5. 获取class对象的三种方法
- Class.forName(“全类名”)
- 类名.class
- 对象.getClass();
6. 利用反射创建对象的两种方式
Class 对象的 newInstance()
: 使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例,但是这种方法要求该 Class 对象对应的类有默认的空构造器。调用 Constructor 对象的 newInstance()
:
//获取 Person 类的 Class 对象
Class clazz = Class.forName("reflection.Person");
//使用.newInstane 方法创建对象
Person p = (Person) clazz.newInstance();
//获取构造方法并创建对象
Constructor c = clazz.getDeclaredConstructor(String.class,String.class,int.class);
//创建对象并设置属性13/04/2018
Person p1 = (Person) c.newInstance("李四","男",20);
7. 反射性能差的原因
反射的性能相对于直接调用来说要差一些,主要原因如下:
-
安全检查:反射在运行时需要进行大量的安全检查(如访问控制检查),这会导致额外的开销。
-
动态解析:反射需要在运行时解析类、方法和字段信息,而这些操作在正常调用中是在编译时完成的。动态解析会带来额外的性能开销。
-
无优化:JVM 对于反射调用的优化能力有限。JIT(Just-In-Time)编译器不能对反射调用进行同样级别的优化,因为反射调用的目标在编译时是未知的。
-
缺少内联:常规方法调用可以被 JVM 内联以减少方法调用的开销,而反射调用由于其动态性,无法享受这种优化。
附录
- Java反射复习 http://t.csdnimg.cn/2gllk