当前位置: 首页 > news >正文

《Effective Java》第一条:用静态工厂方法代替构造器

一、静态工厂方法与构造器不同的优势

1. 静态工厂方法有名称
import java.math.BigInteger;
import java.util.Random;public class PrimeCreationDemo {public static void main(String[] args) {Random random = new Random();  // 创建随机数生成器int bitLength = 512;           // 定义素数的位长(如512位)// 方式1:使用构造器创建素数(不够清晰,需要额外参数和解释)// - 构造器 new BigInteger(int bitLength, int certainty, Random rnd) 需要指定"certainty"(确定性参数)// - certainty 值越高,生成素数的概率越大,但开发者需手动选择值(如100),增加理解负担// - 代码可读性差:参数含义不直观,且容易出错int certainty = 100;  // 手动指定确定性参数(常见值)BigInteger primeViaConstructor = new BigInteger(bitLength, certainty, random);// 方式2:使用静态工厂方法创建素数(更清晰、简洁)// - 方法 BigInteger.probablePrime(int bitLength, Random rnd) 封装了内部逻辑// - 无需关心额外参数(如 certainty),默认使用合理值,代码一目了然// - 命名直观:方法名"probablePrime"直接表达了目的BigInteger primeViaFactory = BigInteger.probablePrime(bitLength, random);// 输出结果以验证(可选)System.out.println("使用构造器创建的素数: " + primeViaConstructor);System.out.println("使用静态工厂创建的素数: " + primeViaFactory);}
}

ps:BigInteger类中certainty值主要用于素数的生成,但是随机大素数判断成本极高,使用的是一种算法,certainty用于2^(-certainty),2^(-certainty)表示不是素数的概率,因此certainty越大,是素数的概率越大。

2. 不必每次调用时都创建一个新对象
public class LessOccupy {public static void main(String[] args) {// 使用构造器创建对象 - 每次都会创建新实例Boolean b1 = new Boolean(true);Boolean b2 = new Boolean(true);System.out.println("构造器创建的对象是否相同: " + (b1 == b2));  // 输出 false// 使用静态工厂方法 - 复用现有实例Boolean b3 = Boolean.valueOf(true);Boolean b4 = Boolean.valueOf(true);System.out.println("静态工厂创建的对象是否相同: " + (b3 == b4));  // 输出 true// 验证内存地址差异System.out.println("构造器实例地址: " + System.identityHashCode(b1));System.out.println("构造器实例地址: " + System.identityHashCode(b2));System.out.println("静态工厂实例地址: " + System.identityHashCode(b3));}
}

其他体现该优势的现成技术:

  1. 包装类缓存机制

    1. Integer.valueOf(int):对-128~127范围内的整数复用对象
    2. Long.valueOf(long):对-128~127范围内的长整数复用对象
    3. Byte.valueOf(byte):所有字节值均被缓存复用
  2. 字符串常量池
  3. 枚举单例模式
  4. 连接池技术
  5. 享元模式实现
// 如java.awt.Color中的颜色缓存
Color red1 = Color.RED;
Color red2 = Color.RED;  // 相同引用
3. 可以返回原返回类型的任何子类
public class Sonable {public static void main(String[] args) {// 静态工厂方法返回List接口的不同子类实现List<String> emptyList = Collections.emptyList();List<String> singletonList = Collections.singletonList("Java");List<String> unmodifiableList = Collections.unmodifiableList(Arrays.asList("A", "B"));System.out.println("emptyList 实际类型: " + emptyList.getClass().getName());System.out.println("singletonList 实际类型: " + singletonList.getClass().getName());System.out.println("unmodifiableList 实际类型: " + unmodifiableList.getClass().getName());}
}

4. 根据传入的枚举类参数决定返回对象的实际类型
public class DiffParaDiffNew {// 定义小规模枚举(<=64个元素)enum SmallSizeEnum { A, B, C }// 定义大规模枚举(>64个元素)enum LargeSizeEnum {E01, E02, E03, E04, E05, E06, E07, E08, E09, E10,E11, E12, E13, E14, E15, E16, E17, E18, E19, E20,E21, E22, E23, E24, E25, E26, E27, E28, E29, E30,E31, E32, E33, E34, E35, E36, E37, E38, E39, E40,E41, E42, E43, E44, E45, E46, E47, E48, E49, E50,E51, E52, E53, E54, E55, E56, E57, E58, E59, E60,E61, E62, E63, E64, E65  // 65个元素}public static void main(String[] args) {// 静态工厂方法根据参数返回不同实现类Set<SmallSizeEnum> smallSet = EnumSet.noneOf(SmallSizeEnum.class);Set<LargeSizeEnum> largeSet = EnumSet.noneOf(LargeSizeEnum.class);// 验证实际返回的类名System.out.println("小枚举集合实现类: " + smallSet.getClass().getName());System.out.println("大枚举集合实现类: " + largeSet.getClass().getName());smallSet.add(SmallSizeEnum.A);largeSet.add(LargeSizeEnum.E01);System.out.println(smallSet);System.out.println(largeSet);}
}

进一步优势在于:

1. 用户只知道会返回EnumSet的子类,但是并不用考虑有多少个子类、使用哪一个子类。

2. 服务侧在对EnumSet更新迭代时,不管是添加还是删除多少子类,客户端无感知。

5. 根据传入的类名动态创建对象实例
public class DynamicObjectFactory {/*** 静态工厂方法:根据传入的类名动态创建对象实例* @param className 目标类的全限定名* @return 新创建的实例(实际类型在编译期未知)* @throws Exception 处理反射相关异常*/public static Object createInstance(String className) throws Exception {// 动态加载类(该类在编译工厂代码时可能不存在)Class<?> targetClass = Class.forName(className);// 获取无参构造器Constructor<?> constructor = targetClass.getDeclaredConstructor();// 创建新实例return constructor.newInstance();}// 测试用例public static void main(String[] args) throws Exception {// 使用场景0:创建编译时已知的类Object obj0 = createInstance("org.learn.chapter1.static_factory_method.Name");System.out.println("创建对象类型: " + obj0.getClass().getName());// 使用场景1:创建编译时未知的类Object obj1 = createInstance("com.example.DynamicService");System.out.println("创建对象类型: " + obj1.getClass().getName());// 使用场景2:运行时动态切换实现类Object obj2 = createInstance("com.example.AlternativeServiceImpl");System.out.println("创建对象类型: " + obj2.getClass().getName());}
}

可以动态创建编译时未知的类——"com.example.DynamicService"

经典用法如:JDBC,一个服务有多个服务商的实现。

二、静态工厂方法的主要缺点

1. 若类不含公有 / 受保护构造器,仅通过静态工厂创建,则该类无法被继承(如 java.util.Collections 的内部子类)
2. 程序员很难发现它们。

需要规范接口命名和注释

http://www.dtcms.com/a/471104.html

相关文章:

  • 怎么做可以访问网站连接加密互联网营销模式
  • Diff-Shadow阴影去除
  • 怎么去接网站来做天津手机网站建设制作
  • 引擎搜索入口aso优化重要吗
  • 做外贸 需要做网站吗知名网站定制报价
  • 四川刚刚发布的最新新闻seo标题优化
  • 一文读懂 Flink Exactly-Once 保证机制深度解析
  • wordpress批量发布内容好的seo平台
  • Unity框架YouYouFramework学习第1篇:游戏入口
  • 专业的建设网站服务公司.网站建设课程设计
  • lnmp利用wordpress网站内链优化策略
  • 宁波做网站的哪个好logo设计多少钱
  • 昂瑞微:科创板逐浪者,射频“芯”征程的领航旗舰
  • Cyanine5.5-PEG-OH,在近红外区发射可用于活体成像
  • 网站注册建设外网代理服务器网站
  • Python文件访问
  • 静态网站设计找国外公司做网站
  • 建网站安全大型科技网站建设
  • Mysql初阶第六讲:Mysql内置函数
  • 怒江州建设局网站企业备案网站花溪村镇建设银行网站
  • 网站搭建合同模板2024很有可能再次封城吗
  • Terminal-Bench:AI 代理终端任务基准测试框架正式发布
  • 国测开始整顿CISP乱价现象,对我们有什么影响呢
  • vps搭建asp网站如何做营销型手机网站优化
  • kanass入门到实战(15) - 如何管理项目集
  • 修改el-popover的最小宽度不生效,如何解决
  • 网站图片用什么做的孝感建设局网站
  • 天津营销型网站建设网站推荐广告模板
  • Java 面试高频题:HashMap 与 ConcurrentHashMap 深度解析(含 JDK1.8 优化与线程安全原理)
  • 做特卖的网站有外贸人才网属于什么电子商务模式