博主介绍:💐大家好,我是不行,还得练
博客主页:🔍@不行,还得练的个人主页
————👀努力坚持向技术大牛看齐的菜鸟
————🌊时代浪潮,不进则退
🌸本文章为个人在学习中遇到的困难及解决方案,对学习内容的知识总结等等,希望对您有帮助,初入博客,文章简陋粗浅,如有错误,欢迎批评指正✌
文章目录
前言
当想要获取一个类的实例时,可以通过构造函数以及静态工厂方法的方式,*例如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);