面试题1:单例模式
题目:请简述单例模式的实现方式,并说明线程安全的单例模式应该如何实现。
考察点:
- 对单例模式基本概念的理解。
- 对线程安全问题的处理能力。
- 熟悉Java语言的特性,如静态变量、静态代码块、构造函数等。
参考答案:
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。常见的单例模式实现方式包括懒汉式、饿汉式、双重校验锁(DCL)和枚举实现。
- 懒汉式:在第一次使用时才初始化实例,但这种实现方式在多线程环境下可能会产生多个实例。
- 饿汉式:在类加载时就初始化实例,保证了线程安全,但无法实现懒加载。
- 双重校验锁(DCL):结合了懒汉式和线程安全的优点,通过双重校验锁的方式确保线程安全。代码示例如下:
public class Singleton { private static volatile Singleton instance = null; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
- 枚举实现:利用Java枚举的特性实现单例,天然线程安全且防止反序列化破坏单例。
public enum Singleton { INSTANCE; public void doSomething() { // 实现业务逻辑 } }
拓展问题:
- 如何防止单例被反射破坏?
- 如何防止单例在反序列化时被破坏?
面试题2:工厂模式
题目:请简述工厂模式的种类及其应用场景,并用Java代码实现一个简单的产品工厂。
考察点:
- 对工厂模式(简单工厂、工厂方法、抽象工厂)的理解。
- 对设计模式的灵活应用能力。
- 编码能力。
参考答案:
工厂模式是一种创建型设计模式,用于封装对象的创建逻辑。它有以下几种类型:
- 简单工厂:通过一个工厂类来创建对象,但不符合开闭原则。
- 工厂方法:定义了一个创建对象的接口,由子类决定实例化哪一个类。
- 抽象工厂:创建相关或依赖对象的家族,而不需明确指定具体类。
简单工厂实现示例:
// 产品接口
interface Product {
void show();
}
// 具体产品A
class ProductA implements Product {
@Override
public void show() {
System.out.println("Product A");
}
}
// 具体产品B
class ProductB implements Product {
@Override
public void show() {
System.out.println("Product B");
}
}
// 工厂类
class ProductFactory {
public static Product createProduct(String type) {
if ("A".equals(type)) {
return new ProductA();
} else if ("B".equals(type)) {
return new ProductB();
}
return null;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Product product = ProductFactory.createProduct("A");
product.show();
}
}
拓展问题:
- 简单工厂和工厂方法的区别是什么?
- 抽象工厂模式的优缺点是什么?
面试题3:观察者模式
题目:请简述观察者模式的原理,并用Java代码实现一个简单的观察者模式示例。
考察点:
- 对观察者模式的理解。
- 对Java语言中接口和回调机制的掌握。
- 编码能力。
参考答案:
观察者模式是一种行为型设计模式,定义了对象间的一种一对多的依赖关系,当一个对象(被观察者)改变时,所有依赖于它的对象(观察者)都会得到通知并自动更新。
实现示例:
// 观察者接口
interface Observer {
void update(String message);
}
// 被观察者接口
interface Subject {
void register(Observer obj);
void unregister(Observer obj);
void notifyObservers();
}
// 具体被观察者
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String message;
@Override
public void register(Observer obj) {
observers.add(obj);
}
@Override
public void unregister(Observer obj) {
observers.remove(obj);
}
@Override
public void notifyObservers() {
for (Observer obj : observers) {
obj.update(message);
}
}
public void setMessage(String message) {
this.message = message;
notifyObservers();
}
}
// 具体观察者
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received message: " + message);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("Observer 1");
Observer observer2 = new ConcreteObserver("Observer 2");
subject.register(observer1);
subject.register(observer2);
subject.setMessage("Hello, Observers!");
subject.unregister(observer1);
subject.setMessage("Hello again!");
}
}
拓展问题:
- 观察者模式在Java中的应用实例是什么(如事件监听机制)?
- 如何优化观察者模式以避免内存泄漏?