第29周 面试题精讲(4)
Java面试题详解
一、简单工厂和工厂方法到底有哪些不同?
问题:简单工厂和工厂方法有哪些区别?
答案:
- 简单工厂:
- 通过一个工厂类实现对象创建,隐藏创建细节。
- 所有对象创建基于一个方法,通过参数不同返回不同对象。
- 客户端直接通过工厂方法获取对象,与工厂类解耦。
- 新增产品时需修改工厂类代码,违反开闭原则。
- 工厂方法:
- 提供抽象工厂接口,每种产品对应具体工厂。
- 工厂接口定义创建方法,具体工厂实现该方法创建对应产品。
- 客户端面对具体工厂实例化后调用方法获取对象。
- 新增产品只需新增对应工厂和产品,不修改现有代码,符合开闭原则。
示例:
// 简单工厂
public class SimpleFactory {
public static Product createProduct(String type) {
if ("A".equals(type)) {
return new ProductA();
} else if ("B".equals(type)) {
return new ProductB();
}
return null;
}
}
// 工厂方法
public interface Factory {
Product createProduct();
}
public class FactoryA implements Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
public class FactoryB implements Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
二、请介绍观察者模式,以及它的使用场景
问题:什么是观察者模式,它的应用场景有哪些?
答案:
- 定义:定义对象间一对多依赖关系,当一个对象状态改变时,所有依赖对象自动更新。
- 角色:
- 目标(Subject):被观察对象,维护观察者列表,提供注册、移除、通知方法。
- 观察者(Observer):抽象角色,定义更新接口。
- 具体目标:实现目标类,维护自身状态,状态变化时通知观察者。
- 具体观察者:实现观察者接口,维护指向目标的引用,实现更新逻辑。
- 使用场景:
- 界面交互(如按钮点击事件)。
- 数据变化联动(如在线拍卖新出价通知其他出价者)。
- 消息订阅与发布(如群消息通知)。
示例:
// 目标类
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(this);
}
}
// 模拟状态变化
public void setState(String state) {
// 状态改变逻辑
notifyObservers();
}
}
// 观察者接口
public interface Observer {
void update(Subject subject);
}
// 具体观察者
public class ConcreteObserver implements Observer {
@Override
public void update(Subject subject) {
// 更新逻辑
}
}
三、静态代理与动态代理有什么区别?
问题:静态代理与动态代理的区别是什么?
答案:
- 静态代理:
- 手动创建代理类,实现与目标类相同接口。
- 代理类持有目标类实例,通过代理类方法调用目标类方法,并在前后增加扩展逻辑。
- 灵活性差,每新增一个目标类需创建对应代理类。
- 动态代理:
- 使用反射机制或字节码增强技术动态生成代理类。
- JDK动态代理基于接口,利用反射生成代理类,通过InvocationHandler处理方法调用。
- CGlib动态代理基于目标类字节码生成子类,重写方法增加扩展逻辑。
- 灵活性高,无需手动创建代理类,尤其适用于大量目标类的场景。
示例:
// 静态代理
public interface Service {
void doSomething();
}
public class RealService implements Service {
@Override
public void doSomething() {
// 目标方法
}
}
public class ProxyService implements Service {
private Service realService;
public ProxyService(Service realService) {
this.realService = realService;
}
@Override
public void doSomething() {
// 前置处理
realService.doSomething();
// 后置处理
}
}
// 动态代理
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置处理
Object result = method.invoke(target, args);
// 后置处理
return result;
}
}
// 使用动态代理
Service service = (Service) Proxy.newProxyInstance(
Service.class.getClassLoader(),
new Class[]{Service.class},
new DynamicProxy(new RealService())
);
四、请说明适配器模式的作用
问题:适配器模式的作用是什么?
答案:
- 定义:将两个不兼容的接口进行衔接,使它们能够互联互通。
- 应用场景:
- 系统迁移,上游接口变化,下游调用者需适配新接口。
- 旧对象在新系统中运行,通过适配器完成接口转换。
- 实现方式:
- 适配器实现目标接口。
- 适配器持有目标对象。
- 适配器重写目标接口方法,完成数据或接口转换。
示例:
// 目标接口
public interface TargetInterface {
void operation();
}
// 需要适配的类
public class Adaptee {
public void specificOperation() {
// 特定操作
}
}
// 适配器
public class Adapter implements TargetInterface {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void operation() {
adaptee.specificOperation();
}
}