火柴人战争4无敌MOD
68.98MB · 2025-11-12
《Effective Java》条目一的核心结论是:优先使用静态工厂方法替代构造器,因为它在命名、灵活性、性能等方面具备显著优势,但也存在无法被子类化、不易被发现等局限。
场景:创建一个Phone类,需支持 “普通手机” 和 “折叠屏手机” 两种实例。
public class Phone {
private final String type; // 手机类型:普通/折叠屏
// 构造器:名称固定为Phone,无法区分创建逻辑
public Phone(String type) { // 调用时new Phone("foldable"),语义模糊
this.type = type;
}
// 静态工厂方法:名称直接说明用途
public static Phone createNormalPhone() { // 明确创建“普通手机”
return new Phone("normal");
}
public static Phone createFoldablePhone() { // 明确创建“折叠屏手机”
return new Phone("foldable");
}
}
// 使用对比
Phone p1 = new Phone("foldable"); // 不直观:不知道"foldable"代表什么
Phone p2 = Phone.createFoldablePhone(); // 直观:一眼懂是创建折叠屏手机
这种技术在享元模式下经常使用,如果程序经常请求创建相同的对象,特别是当创建对象的开销大时,利用这种技术开源提升性能。这样的类被称为实例受控的类,对于重复多次的调用,静态工厂方法可以返回同一个对象。静态工厂方法可控制对象创建,对频繁使用的实例(如单例、枚举常量)进行缓存,避免重复创建,节省内存。
场景:创建Color类,缓存 “红、绿、蓝” 三种基础颜色,避免重复 new。
public class Color {
private final String name;
// 缓存池:存储已创建的基础颜色实例
private static final Map<String, Color> COLOR_CACHE = new ConcurrentHashMap<>();
// 私有构造器:禁止外部直接new
private Color(String name) {
this.name = name;
}
// 静态工厂方法:先查缓存,无则创建并缓存
public static Color getInstance(String name) {
// 关键:先从缓存取,避免重复创建
return COLOR_CACHE.computeIfAbsent(name, Color::new);
}
// 测试:多次调用getInstance("red"),返回同一个对象
public static void main(String[] args) {
Color red1 = Color.getInstance("red");
Color red2 = Color.getInstance("red");
System.out.println(red1 == red2); // true(同一对象,未重复创建)
}
}
静态工厂方法的返回类型可以是父类,实际返回的是子类实例,灵活扩展 API(用户无需知道子类存在)。
场景:Shape作为父类,静态工厂方法返回Circle/Rectangle子类实例。
// 父类:抽象形状
public abstract class Shape {
// 静态工厂方法:返回Shape的子类实例
public static Shape getShape(String type) {
return switch (type) {
case "circle" -> new Circle(); // 返回子类Circle
case "rectangle" -> new Rectangle(); // 返回子类Rectangle
default -> throw new IllegalArgumentException("未知形状");
};
}
public abstract void draw(); // 抽象方法
}
// 子类1:圆形(无需对外暴露)
class Circle extends Shape {
@Override
public void draw() {
System.out.println("画圆形");
}
}
// 子类2:矩形(无需对外暴露)
class Rectangle extends Shape {
@Override
public void draw() {
System.out.println("画矩形");
}
}
// 使用:用户只依赖Shape父类,无需知道子类存在
public class Test {
public static void main(String[] args) {
Shape circle = Shape.getShape("circle");
circle.draw(); // 画圆形(实际是Circle子类在执行)
}
}
静态工厂方法可根据条件动态选择返回的类(如根据版本、配置切换实现类),不影响外部调用。
场景:ImageReader根据图片格式(JPG/PNG),动态返回不同的实现类。
// 父接口:图片读取器
public interface ImageReader {
void read(String path);
// 静态工厂方法:根据格式动态返回实现类
public static ImageReader getReader(String format) {
if ("jpg".equalsIgnoreCase(format)) {
return new JpgImageReader(); // JPG格式返回JpgReader
} else if ("png".equalsIgnoreCase(format)) {
return new PngImageReader(); // PNG格式返回PngReader
}
throw new IllegalArgumentException("不支持的格式");
}
}
// JPG实现类
class JpgImageReader implements ImageReader {
@Override
public void read(String path) {
System.out.println("读取JPG图片:" + path);
}
}
// PNG实现类
class PngImageReader implements ImageReader {
@Override
public void read(String path) {
System.out.println("读取PNG图片:" + path);
}
}
// 使用:用户无需关心具体实现类,按格式调用即可
public class Test {
public static void main(String[] args) {
ImageReader jpgReader = ImageReader.getReader("jpg");
jpgReader.read("photo.jpg"); // 读取JPG图片:photo.jpg
}
}
若类的构造器是private,且仅通过静态工厂方法创建实例,子类无法调用父类构造器,导致无法继承。
public class Utils {
// 私有构造器:禁止外部new,也禁止子类调用
private Utils() {}
// 静态工厂方法:创建Utils实例
public static Utils getInstance() {
return new Utils();
}
}
// 错误:无法继承Utils(父类无公有构造器,子类无法初始化)
class MyUtils extends Utils {
// 编译报错:Implicit super constructor Utils() is not visible for default constructor.
}
静态工厂方法(如getInstance/of)和普通静态方法(如Math.abs)在语法上完全一致,开发者可能找不到创建实例的入口(构造器有new关键字提示,静态工厂没有)。
场景:User类同时有静态工厂方法和普通静态方法,开发者可能忽略创建实例的方法。
public class User {
private String name;
private User(String name) {
this.name = name;
}
// 静态工厂方法:用于创建User实例(但和普通静态方法无语法区别)
public static User of(String name) {
return new User(name);
}
// 普通静态方法:用于处理用户名(和of()语法完全一致)
public static String formatName(String name) {
return name.trim().toUpperCase();
}
}
// 使用问题:开发者可能只看到formatName(),忽略of()是创建实例的方法
public class Test {
public static void main(String[] args) {
String upperName = User.formatName("zhangsan"); // 容易发现
User user = User.of("zhangsan"); // 若不知道of()是工厂方法,可能找不到创建入口
}
}
相比传统的new构造器,静态工厂方法主要有 5 个优势:
BigInteger.probablePrime(100)比new BigInteger(100)更清晰,一看就知道是创建 “可能为素数” 的实例。Boolean.valueOf(boolean),它只返回Boolean.TRUE和Boolean.FALSE两个静态常量,从不新建对象。java.util.Collections的静态方法(如emptyList())返回的是隐藏的私有子类实例,而非List接口的直接实现,用户无需关心具体实现类。Map<String, List<String>> map = HashMap.newHashMap(),比new HashMap<String, List<String>>()更简洁(Java 7 之前的泛型简化场景)。