简介:这份PDF面向Java求职者与初中级开发者,围绕反射专题整理11道高频面试题,内容涵盖除new之外的动态创建对象方式、反射与new的效率差异、反射在JDBC及Hibernate、Struts等框架中的典型用途,并串联Class、Field、Method、Constructor等核心类、四类获取Class对象的途径以及反射使用步骤。压缩包共1个PDF文件,约569KB,体量轻便,适合面试前速览、知识点串讲和查漏补缺。已有229人学习下载,可作为Java反射复习的参考材料。读者能从中梳理反射调用步骤、动态实例化对象、私有成员访问与setAccessible等细节,也能理解反射带来的灵活性与性能、封装性取舍,并据此整理常见追问的答题框架。同时可对照反射的优缺点与优化方案,如关闭安全检查、缓存实例、借助字节码工具提升速度,形成更完整的复习知识体系。
1. 反射面试的分水岭:会写 newInstance 只是入门
Java 反射面试题看着只有 11 道,但面试官一般不照着题目念。他更可能随手抛一句:“不用 new,你怎么造对象?”如果你只答得出Class.newInstance(),接下来大概率会被追问:反射和 new 谁快、慢在哪、怎么补;JDBC 为什么离不开反射;setAccessible(true)到底关掉了什么检查。这场面试考的不是 API 背诵,而是你能不能把“运行时才确定类”这件事讲成一条完整链路:拿到 Class 对象、读结构、造实例、调方法、处理性能与封装性的代价。11 道题基本都挂在这条链路上,适合正在准备 Java 后端面试、又对反射只停留在“听说过”阶段的人,把答案从一句背成一段。
2. 考点分布:11 道题背后的四条主线
把这 11 道题摊开看,重复率很高,本质是四条主线在反复绕:怎么拿到 Class、怎么用反射造对象和调方法、反射为什么慢又为什么危险、框架和 JDBC 为什么非它不可。面试官问法会变,但落点跑不出这四块。先看清分值分布,再背答案,效率差很多。
从实际面试频率看,四条主线的权重大致是这样:
| 考点主线 | 对应题号 | 面试出现频率 | 常见问法 |
|---|---|---|---|
| 获取 Class 对象的四种方式 | 5、10 | 极高,几乎必问 | “有几种写法,区别是什么” |
| 反射创建对象与调用方法 | 1、11 | 极高,常配代码 | “写一下不用 new 造对象” |
| 反射的优缺点与性能 | 2、7 | 高,常作追问 | “为什么慢,怎么优化” |
| 反射的应用场景与 API | 3、4、6、8、9 | 中高,偏理解 | “JDBC 哪里用了反射” |
频率高不等于答得长。获取 Class 那题,面试官想听的是四种方式的名字加一句差异,不是让你把Class.forName的源码背一遍。造对象那题相反,光说“用 newInstance”会被追着要代码。性能那题最容易翻车,因为大多数人只会说“反射慢”,说不出慢在哪、怎么缓解。
2.1 获取 Class 对象的四种方式与差异
这是反射的入口题,也是整条链路的第一步。原料里给了四种:Class.forName("类的全路径")、类名.class、对象名.getClass()、基本类型包装类的TYPE属性。答这题的关键不是列四条,而是说清它们各自什么时候用、有没有副作用。
Class.forName传的是字符串全限定名,最常用于配置驱动的场景,因为它可以在运行时才决定加载哪个类,JDBC 加载驱动就是这条路。它有个容易被忽略的点:默认会触发类的静态初始化,也就是静态代码块会执行。这一点面试官很爱追,因为它是“为什么 forName 能加载驱动”的直接原因。
类名.class是编译期就确定的写法,不依赖对象,也不会触发静态初始化,适合在代码里已经明确知道类型时用。对象名.getClass()必须手上先有一个实例,返回的是这个实例运行时的真实类型,注意它和类名.class在多态场景下可能不一致。第四种Integer.TYPE这类写法,拿到的是基本类型int的 Class 对象,和Integer.class不是同一个东西,这个细节被问到过不少次。
// 方式一:Class.forName,字符串全限定名,会触发静态初始化 Class<?> c1 = Class.forName("com.example.demo.Person"); // 方式二:类名.class,编译期确定,不触发静态初始化 Class<?> c2 = Person.class; // 方式三:对象.getClass(),返回运行时真实类型 Person p = new Person(); Class<?> c3 = p.getClass(); // 方式四:包装类的 TYPE 属性,拿到的是基本类型 Class<?> c4 = Integer.TYPE; // int Class<?> c5 = Integer.class; // java.lang.Integer,与 c4 不同代码里c1和c2指向同一个 Class 对象,因为一个类在 JVM 里只有一个 Class 实例,这点可以顺口带出来,属于加分细节。c4和c5不相等,是包装类题的经典陷阱。答这题时先说“四种”,再按“是否依赖对象、是否触发初始化、拿到的类型是否一致”三个维度做区分,比平铺四条有说服力。
2.2 反射造对象与调方法的完整写法
第 1 题和第 11 题其实是同一件事的两面:不用 new 怎么造对象,以及造出来之后怎么用。面试官最想听的是两种造对象路径的差别:Class.newInstance()和Constructor.newInstance()。
Class.newInstance()写法最短,但限制很硬:目标类必须有可访问的无参构造器,而且它会把构造器抛出的受检异常原样往外扔,异常处理上比较别扭。Constructor.newInstance()要先通过getDeclaredConstructor(...)拿到指定参数类型的构造器,再传参创建,能选构造方法、能处理受检异常,是实际项目里更常用的写法。答的时候把这条差异讲出来,比只会写第一种强一档。
Class<?> clazz = Class.forName("com.example.demo.Person"); // 路径一:Class.newInstance,要求有无参构造器 Person p1 = (Person) clazz.newInstance(); // 路径二:先取构造器再创建,可指定参数 Constructor<?> c = clazz.getDeclaredConstructor(String.class, String.class, int.class); Person p2 = (Person) c.newInstance("张三", "男", 20); // 取方法并调用 Method m = clazz.getDeclaredMethod("setName", String.class); m.invoke(p2, "李四"); // 取属性并赋值 Field f = clazz.getDeclaredField("name"); f.setAccessible(true); // 私有属性必须开权限 f.set(p2, "王五");注意getDeclaredMethod和getMethod的区别:前者拿本类声明的所有方法包括私有,后者只拿 public 且包含继承来的。私有成员必须setAccessible(true),否则抛IllegalAccessException。invoke的第一个参数是目标实例,静态方法传 null。这几行代码能默写出来,第 11 题基本就稳了。
2.3 反射为什么慢:性能题的答法
“反射和 new 哪个快”是送分题,答“new 快”就够一半分。真正拉开差距的是追问:“慢在哪?”原料给的答案是:反射要先查找类资源,再走类加载器创建,过程繁琐。这个方向对,但太笼统,面试官会继续压。
更完整的答法是分三层。第一层是查找成本:Class.forName要按全限定名定位类、走类加载流程,new 是编译期就确定、直接分配。第二层是调用成本:Method.invoke是动态调用,参数要装箱成 Object 数组,返回值也要转换,JVM 难以像普通方法调用那样做内联优化。第三层是权限检查:每次访问私有成员都要做访问校验。
对应的优化手段原料也给了三条,答的时候要能对上号。setAccessible(true)关掉的是访问权限检查,减少的是第三层成本,但它不改变查找和动态调用的开销,所以别把它说成“反射就不慢了”。缓存 Class 对象和 Method 对象,省的是重复查找,对应第一层。ReflectASM 这类字节码工具,走的是生成字节码直接调用的路子,绕开动态调用,对应第二层。三条各治一个病,能对上这层映射,这题就从背诵变成了理解。
提示:被问到“setAccessible 是不是让反射变快”时,别说“是”,说“只省掉访问检查这一块,查找和动态调用的开销还在”,这个回答更像做过事的人。
3. 高频考点:API、应用场景与封装性代价
第二条主线偏理解,题目不写代码也能答,但答得好不好一眼能看出来。这块包括反射涉及哪几个核心类、JDBC 和框架哪里用了反射、反射破坏封装性意味着什么。它们经常合并成一道开放题:“谈谈你对反射的理解。”
3.1 四个核心类与使用步骤
原料给了四个类:Class、Field、Constructor、Method。答这题不要只报名字,要按“谁是谁的入口、各自管什么”讲。Class 是总入口,代表正在运行的类和接口,所有信息都得先从它拿。Field 管属性,能读能写。Constructor 管构造方法,是造对象的第二条路。Method 管方法,能取信息也能执行。
对应的使用步骤也是三步:先拿 Class 对象,再通过 Class 的方法取出 Method、Field、Constructor,最后用这些对象操作目标实例。这三步是反射所有代码的骨架,第 11 题的代码就是按这个骨架写的。面试时如果一时想不起某个 API 名,先把三步讲出来,再往里填,比卡在一个方法名上强。
| 核心类 | 管的范围 | 典型方法 | 常见用途 |
|---|---|---|---|
| Class | 类与接口的整体信息 | forName、getDeclaredMethods | 反射入口 |
| Field | 成员变量 | get、set、setAccessible | 读写属性,含私有 |
| Constructor | 构造方法 | getDeclaredConstructor、newInstance | 指定参数造对象 |
| Method | 方法 | getDeclaredMethod、invoke | 动态调用方法 |
这张表能默写,第 6 题和第 8 题就是同一道题。注意java.lang.reflect这个包名,Field、Method、Constructor 都在里面,Class 在java.lang下,写错包名属于无谓失分。
3.2 JDBC 与框架里的反射:场景题怎么答
“哪里会用到反射”这题,原料给的答案是 JDBC 和 Hibernate、Struts 这类框架。只说名字不够,要说清反射在里头干了什么。
JDBC 的经典链路是:代码里只写数据库连接字符串和驱动类名,Class.forName("驱动类全名")在运行时才把驱动类加载进来,触发它的静态代码块去注册驱动,之后才能拿到连接。整个过程编译期根本不知道用的是哪个数据库的驱动,这就是反射存在的意义——把“用哪个类”从编译期推迟到运行期。
框架用反射的逻辑类似但更重。对象和表字段的映射、根据配置创建实例、调用标注了特定注解的方法,都需要在运行时才知道类长什么样。这类题的标准答法是:先说场景,再说反射在这里解决了什么“编译期定不下来”的问题,最后补一句代价。不要泛泛说“框架用了反射所以很灵活”,那等于没说。
3.3 反射破坏封装性:优缺点题的另一半
第 7 题的缺点部分,很多人只答“性能低”,漏掉“破坏封装性”。面试官问这句,想听的是你知不知道私有成员在反射面前形同虚设。
setAccessible(true)一开,private 字段和方法都能读写调用,类的访问控制被绕过。这在框架里是刚需,在业务代码里就是风险:别人约定好的私有状态被外部改了,出问题时很难查。答这题要把两面都说:灵活性是它存在的理由,破坏封装是它要付的账,所以业务代码里能不用就不用,框架层用要控制范围。
注意:这题的高分点不在背优缺点,而在说出“什么时候该用、什么时候不该用”。只列优缺点的答法,容易被判成背书。
4. 易错点:五个最容易被追问翻车的地方
反射这 11 道题,错误集中得惊人。下面五条是面试现场最常被追问到答不上来的点,每条都按“错在哪、为什么错、怎么答对”拆开。
4.1 把 Class.newInstance 当成唯一造对象方式
错在只答一种写法就停。为什么错:面试官问“不用 new 怎么造对象”,期待的是你知道有两条路径并能说差异。Class.newInstance()要求无参构造器,且异常处理不友好;Constructor.newInstance()能选构造器、能包住受检异常。怎么答对:先给两条路径,再补一句“实际项目里后者更常用,因为能指定参数”。
4.2 说 forName 和 类名.class 完全一样
错在忽略副作用。为什么错:两者确实返回同一个 Class 对象,但Class.forName默认会触发类的静态初始化,类名.class不会。这个差异在加载驱动的场景里恰恰是关键。怎么答对:先说“指向同一个 Class 实例”,再补“区别在是否触发静态初始化、是否依赖运行期字符串”。
4.3 把 setAccessible 说成性能优化万能药
错在夸大它的作用。为什么错:它关掉的是访问权限检查,反射慢的主因还包括类查找和动态调用开销,这两块它管不着。怎么答对:分三层讲成本,再说setAccessible只治其中一层,缓存治查找,字节码工具治调用。
4.4 混淆 getMethod 和 getDeclaredMethod
错在两个方法随手用。为什么错:getMethod只返回 public 方法且包含继承的,getDeclaredMethod返回本类声明的所有方法含私有但不含继承。取私有方法用错方法会直接抛NoSuchMethodException。怎么答对:按“要不要私有、要不要继承”两个维度选,私有必用 declared。
4.5 场景题只报框架名不说机制
错在答“Hibernate 用了反射”就结束。为什么错:面试官要的是你理解反射解决了什么编译期定不下来的问题。怎么答对:拿 JDBC 举例,说清“驱动类名写在配置里,运行时 forName 加载并触发静态块注册驱动”,有链路才有分。
5. 答题节奏:把 11 道题压成三句话的练法
反射这块的题,背答案不如背结构。我的习惯是每道题都压成三句话:这句话是什么、它解决什么问题、它的代价是什么。拿造对象那题举例,第一句给两条路径,第二句说它们在“能否指定构造器、异常处理”上的差别,第三句落到“反射造对象比 new 慢,业务代码优先 new”。三句话能站住,追问再怎么变也有得接。
练的时候按这个顺序走一遍,比按题号顺序背有效:
| 练习顺序 | 覆盖题目 | 练到什么程度 |
|---|---|---|
| 第一步 | 获取 Class 四种方式 | 能说出差异和副作用,不卡壳 |
| 第二步 | 造对象 + 调方法代码 | 能默写两条路径和 invoke |
| 第三步 | 性能三层成本 | 能对上三条优化手段 |
| 第四步 | JDBC 场景链路 | 能讲清 forName 到注册驱动 |
| 第五步 | 封装性代价 | 能说出该用和不该用的边界 |
第一步到第二步是硬功夫,代码必须能手写,getDeclaredConstructor的参数类型、invoke的第一个参数是什么,这些细节写错就露怯。第三步和第四步考的是表达,练法是合上资料,用嘴把“反射为什么慢”讲一遍,讲不顺的地方就是没真懂的地方。第五步最容易被忽略,但它决定了你是“会 API”还是“懂取舍”。
有个血泪经验:面试里被问“反射能不能完全替代 new”,别答“能”。正确姿势是先说“技术上大多数场景可以”,再补“但性能和封装性代价决定了它只该出现在编译期定不下来类的地方”,最后收一句“业务代码里我优先 new,框架和配置驱动才用反射”。这个答法把优缺点、场景、取舍一次讲完,面试官通常就不再追了。
从那以后我每次准备这类 API 型面试题,都强制自己走一遍“三句话 + 一张链路图”的流程:先把每道题压成三句话,再把 JDBC 那条链路在纸上默画一遍,画不出来的环节就是下次要被问倒的地方。希望帮到你。
本文还有配套的精品资源,点击获取