创建和销毁对象——用静态工厂方法代替构造器

本文分析了Java中静态工厂方法的优缺点,包括其明确的命名、节省资源、返回不同类型对象的能力以及服务提供者框架的应用。同时指出类无公开构造器的限制和静态工厂方法在API文档中的隐藏性问题。
摘要由CSDN通过智能技术生成

博主介绍:💐大家好,我是不行,还得练
博客主页:🔍@不行,还得练的个人主页
————👀努力坚持向技术大牛看齐的菜鸟
————🌊时代浪潮,不进则退
🌸本文章为个人在学习中遇到的困难及解决方案,对学习内容的知识总结等等,希望对您有帮助,初入博客,文章简陋粗浅,如有错误,欢迎批评指正✌


前言

当想要获取一个类的实例时,可以通过构造函数以及静态工厂方法的方式,*例如Boolean.valueOf(boolean)就是典型的静态工厂方法。*但是更多时候静态工厂方法比构造器更加合适,多数情况下应该先考虑静态工厂方法来代替构造器


首先,先理解何为构造函数以及静态工厂方法:
在 Java 中,使用 new 关键字来实现对象的创建,便是构造方法
例如:

Date date = new Date();
Student student = new Student();
...

不通过 new,而是用一个静态方法来对外提供自身实例的方法,即为静态工厂方法
例如:

Calendar calendar = Calendar.getInstance();
Student student = Student.newInstance();
Integer number = Integer.valueOf("3");
...

当我们使用 new 来构造一个新的类实例时,其实就是告诉 JVM 我们需要一个新的实例。JVM 就会自动在内存中开辟一片空间,然后调用构造函数来初始化成员变量,最终把引用返回给调用方。

一、优势

1、静态方法有确切的名称

构造函数中的参数本身没有确切的描述被返回的对象,换成具有适当名称的静态工厂方法时更容易被使用及阅读。

例如,构造方法BigInteger(int,int,Random) 返回的BigInteger可能为素数,使用静态工厂方法就可以用名为BigInteger.probablePrime的方法来表示,这样更加显而易见。

2、无需每次调用都创建新的对象

例如:

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

实例中Boolean.valueOf(boolean b)实际返回的是静态存储的对象,不会重新 new 一个对象来增加对性能的消耗。

3、可以返回任何子类的对象

例如:

public static <T> List<T> unmodifiableList(List<? extends T> list) {
    return (list instanceof RandomAccess ?
            new UnmodifiableRandomAccessList<>(list) :
            new UnmodifiableList<>(list));
}

Java的Collections类通过静态工厂方法共计返回45种不同的实现类,这些实现类对用户不可见,可见的是List 、Map这样的基类。如Collections.unmodifiableList会根据参数list是否支持随机访问,返回不同类型的不可变List。

4、返回对象的类可以随参数的不同而变化

例如:

// Thread.State是少于64个元素的enum
EnumSet<Thread.State> es1 = EnumSet.allOf(Thread.State.class);
// Character.UnicodeScript是多于64个元素的enum
EnumSet<Character.UnicodeScript> es2 = EnumSet.allOf(Character.UnicodeScript.class);
// 打印出es1的类型为RegularEnumSet
System.out.println(es1.getClass());
// 打印出es2的类型为JumboEnumSet
System.out.println(es2.getClass());

EnumSet的静态工厂方法根据参数enum的大小,返回不同的子类实例。如果有64个或更少的元素,返回一个基于long类型的RegularEnumSet实例;否则返回一个基于long[] 类型的 JumboEnumSet实例。

5、无需考虑返回对象的类是否存在

这种灵活的静态工厂方法构成了服务提供者框架的基础。

例如:
JDBC的API中服务提供者框架是指:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把它从多个实现中解耦出来。


二、劣势

1、类如果不含公有的或者受保护的构造器,则不能被子类化

例如,要想将Collections Framework 中的任何便利的实现类子类化是不可能的。

2、程序员很难发现

在API文档中,没有像构造器那样在API文档中明确标识出来,因此,对于提供了静态工厂方法而不是构造器的类来说,要查明如何实例化一个类是非常困难的。


三、惯用名称

下面是一些静态工厂方法的惯用名称:

// from 类型转换方法
Date d = Date.from(instant);
// of 聚合方法
Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
// valueOf 比 from 和 of 更烦琐的一种替代方法
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
// instance or getInstance 返回的实例是通过方法参数来描述的
StackWalker luke = StackWalker.getInstance(options);
// create or newInstance 类似于 instance 或者 getInstance 
Object newArray = Array.newInstance(classObject, arrayLen);
// getType 类似于 getInstance 
FileStore fs = Files.getFileStore(path);
// newType 类似于 newInstance 
BufferedReader br = Files.newBufferedReader(path);
// type getType 和 newType 的简版
List<Complaint> litany = Collections.list(legacyLitany);
  • 25
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值