北京JAVA基础面试30天打卡01
希望大家坚持下去,30 天只更新核心面试题 ~
1. 接口和抽象类的区别
特性 | 接口 (Interface) | 抽象类 (Abstract Class) |
---|---|---|
定义 | 使用 interface 关键字定义,JDK 8 起支持默认方法和静态方法。 | 使用 abstract class 关键字定义,包含抽象方法或具体方法。 |
继承 | 类可以实现多个接口(多实现)。 | 类只能继承一个抽象类(单继承)。 |
成员变量 | 只能定义 public static final 的常量(默认)。 | 可以定义任意类型的成员变量(包括实例变量)。 |
方法 | JDK 8 前只能有抽象方法;JDK 8 起支持默认方法和静态方法。 | 可以有抽象方法和具体方法。 |
构造方法 | 没有构造方法。 | 可以有构造方法,供子类调用。 |
访问修饰符 | 方法默认 public,无法定义 protected 或 private 方法。 | 方法和变量可以有任意访问修饰符。 |
使用场景 | 定义行为规范,强调契约式编程,适合松耦合设计。 | 提供部分实现,适合具有共同逻辑的类层次结构。 |
总结:
- 接口适合定义规范,强调“做什么”,支持多实现,灵活性高。 自上而下,规定行为。
- 抽象类适合代码复用,强调“是什么”,提供部分实现,适合有共同行为的类。 自下而上,抽取共性,一般重构用。
其他:
Java8:引l入了default和static方法,使得接口不仅仅
是方法的声明,还可以提供具体的实现。default方法允
许在接口中添加新的方法实现,而不影响己经实现该接口
的类。
Java9:引l入了私有方法,允许在接口中定义私有方法,
用于default方法的内部逻辑复用。
Java 14:引l入了sealed接口(仅在某些子类中使用),
进一步增强了接口的功能
2. JDK 动态代理和 CGLIB 动态代理的区别
特性 | JDK 动态代理 | CGLIB 动态代理 |
---|---|---|
实现方式 | 基于接口,使用 Java 的 java.lang.reflect.Proxy 类。 | 基于继承,使用 ASM 字节码操作框架生成子类。 |
依赖 | 目标类必须实现接口。 | 目标类无需实现接口,但不能是 final 类或方法。 |
代理对象生成 | 通过反射生成实现接口的代理类。 | 通过字节码生成目标类的子类。 |
性能 | 性能稍低(依赖反射调用)。 | 性能较高(直接字节码操作,调用效率接近原生)。 |
使用场景 | Spring 默认使用,AOP 中目标类有接口时优先选择。 | Spring AOP 中目标类无接口时使用,或需要代理非接口方法。 |
方法调用 | 通过 InvocationHandler 的 invoke 方法拦截。 | 通过 MethodInterceptor 的 intercept 方法拦截。 |
局限性 | 只能代理接口定义的方法,无法代理非接口方法。 | 无法代理 final 类或 final 方法。 |
总结:
- JDK 动态代理:适合有接口的场景,代码简单,依赖 JDK 原生支持,但性能稍逊。
- CGLIB 动态代理:适合无接口的场景,性能更高,但依赖第三方库(如 ASM),对 final 类无能为力。
- Spring 中的选择:Spring AOP 默认使用 JDK 动态代理,若目标类无接口则自动切换到 CGLIB。
其他:
1.jdk6下,在运行次数较少的情况下,jdk动态代理与
cglib差距不明显,甚至更快一些;而当调用次数增加
之后,cglib表现稍微更快一些
2.jdk7下,情况发生了逆转!在运行次数较少
(1,000,000)的情况下,jdk动态代理比cglib快了差
不多30%;而当调用次数增加之后(50,000,000),动
态代理比cglib快了接近1倍
3.jdk8表现和jdk7基本一致
3. Java 的反射机制及其应用
什么是反射? Java 反射机制允许程序在运行时动态获取类的元信息(如类名、方法、字段、构造器等)并操作这些信息。核心类位于 java.lang.reflect 包,如 Class、Method、Field、Constructor。
如何应用反射?
-
获取 Class 对象
// 三种方式Class<?> clazz1 = Class.forName("java.util.ArrayList");Class<?> clazz2 = ArrayList.class;Class<?> clazz3 = new ArrayList<>().getClass();
-
操作构造器
Constructor<?> constructor = clazz1.getDeclaredConstructor();constructor.setAccessible(true); // 绕过访问限制Object instance = constructor.newInstance(); // 创建实例
-
操作方法
Method method = clazz1.getDeclaredMethod("add", Object.class);method.setAccessible(true);method.invoke(instance, "test"); // 调用方法
-
操作字段
Field field = clazz1.getDeclaredField("elementData");field.setAccessible(true);Object value = field.get(instance); // 获取字段值
应用场景:
- 框架开发:如 Spring(通过反射实例化 Bean)、Hibernate(动态映射实体类字段)。
- 动态代理:JDK 动态代理依赖反射实现方法调用。
- 序列化/反序列化:如 JSON 库(FastJSON、Gson)通过反射读写对象字段。
- 工具类:如单元测试框架(JUnit)通过反射调用测试方法。
- 插件化开发:动态加载未知的类或方法。
优缺点:
- 优点:灵活性高,支持运行时动态操作,适合框架和通用工具开发。
- 缺点:
- 性能开销大(反射调用比直接调用慢)。
- 安全性问题(绕过访问限制可能导致不可预期的行为)。
- 代码可读性差,维护成本高。
注意事项:
- 尽量缓存 Class、Method 等对象以减少反射开销。
- 谨慎使用 setAccessible(true),可能引发安全漏洞。
- 在高性能场景下,优先考虑非反射方案(如字节码操作或直接调用)。
总结**:
- 接口和抽象类在继承、方法实现和使用场景上各有侧重,接口更灵活,抽象类更适合复用。
- JDK 动态代理依赖接口,CGLIB 基于继承,Spring 根据目标类情况自动选择
- 反射机制是 Java 动态性的核心,广泛应用于框架开发,但需注意性能和安全问题
希望大家坚持下去,30 天只更新核心面试题 ~