1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > java中静态工厂_Java静态工厂方法

java中静态工厂_Java静态工厂方法

时间:2024-04-08 12:35:29

相关推荐

java中静态工厂_Java静态工厂方法

相比构造器,静态工厂方法提供实例的优势:

静态工厂方法有名字

使用静态工厂方法比直接使用等效的构造方法更易阅读理解

BigInteger.java

//生成一个可能的质数

public static BigInteger probablePrime(int bitLength, @NonNull Random random) {

return new BigInteger(bitLength, 100, random);

}

每次调用不必创建新对象

相比构造器,静态工厂返回的对象可以是缓存的

Boolean.java

//预先创建的实例

public static final Boolean TRUE = new Boolean(true);

public static final Boolean FALSE = new Boolean(false);

//作重复使用,避免对象的创建和回收,这对那些创建代价较高的类更加有效

public static Boolean valueOf(boolean b) {

return (b ? TRUE : FALSE);

}

返回的对象可以是返回类型的子类

这个子类可以是非公共的,有利于隐藏实现的细节,比如Collections类里面静态方法返回的对象都是非公共的,但不影响客户端调用。

Collections.java

//到了Java8,接口中可以有静态方法,也就是这样的方法可以放在接口中

public static Map singletonMap(K key, V value) {

return new SingletonMap<>(key, value);

}

//在接口中这样的静态成员类必须是public,所以如果上面的静态方法在接口中,这样的类必须独立成文件

private static class SingletonMap

private final K k;

private final V v;

SingletonMap(K key, V value) {

k = key;

v = value;

}

...

}

返回的实现类可以根据方法参数改变

由于上面一条带来的优势,静态工厂方法可以根据方法参数返回实现类,可以更加情况增加或减少实现类,而不影响客户端使用

EnumSet.java

public static > EnumSet noneOf(Class elementType) {

Enum>[] universe = getUniverse(elementType);

if (universe == null)

throw new ClassCastException(elementType + " not an enum");

if (universe.length <= 64)

return new RegularEnumSet<>(elementType, universe);

else

return new JumboEnumSet<>(elementType, universe);

}

返回类型的实现类和静态方法不用同步存在

由于静态方法的返回类型可以是接口,所以当方法写好以后,实现类可能还不存在。这是 service provider frameworks的基础,这个框架有三个元素

a service interface,代表一个实现

a provider registration API ,服务提供者用来注册服务实例

a service access API, 客户用来获取服务实列

还有可选的第四个元素

service provider interface,代表一个服务提供者

以JDBC为例

DriverManager.java

//这个注册方法就是 provider registration API

//Driver是service provider interface,service provider是service的实现

public static synchronized void registerDriver(java.sql.Driver ) throws SQLException {

if(driver != null) {

registeredDrivers.addIfAbsent(new DriverInfo(driver));

} else {

// This is for compatibility with the original DriverManager

throw new NullPointerException();

}

println("registerDriver: " + driver);

}

//方法返回类型Connection 被称为service interface,这个方法就是service access API

public static Connection getConnection(String url) throws SQLException {

java.util.Properties info = new java.util.Properties();

return (getConnection(url, info, Reflection.getCallerClass()));

}

private static Connection getConnection(String url, java.util.Properties info, Class> caller) throws SQLException {

...

//遍历注册的service provider,我们期望的是有可能找不到的

for(DriverInfo aDriver : registeredDrivers) {

if(isDriverAllowed(aDriver.driver, callerCL)) {

try {

Connection con = aDriver.driver.connect(url, info);

if (con != null) {

// Success!

println("getConnection returning " + aDriver.driver.getClass().getName());

return (con);

}

} catch (SQLException ex) {

if (reason == null) {

reason = ex;

}

}

}

}

...

}

每个数据库都可以提供自己的驱动,比如:om.mysql.jdbc.Driver,我们在使用它之前需要加载驱动Class.forName(“com.mysql.jdbc.Driver”);当类加载的时候,就通过静态代码块完成service provider的注册。

在java 6中,可以在配置文件中配置service(可能是一个interface或者abstract class)的provider(即service的实现类)。配置路径是:/META-INF/services/下面。不需要使用Class.forName方法手动加载,ServiceLoader为我们提供了框架。

com.mysql.jdbc.Driver.java

static {

try {

java.sql.DriverManager.registerDriver(new Driver());

} catch (SQLException E) {

throw new RuntimeException(“Can’t register driver!”);

}

}

返回与线程相关的实列

结合ThreadLocal,静态工厂方法可以返回与线程相关的独立实列,以下来自Android中的Looper类

Looper.java

static final ThreadLocal sThreadLocal = new ThreadLocal();

public static void prepare() {

prepare(true);

}

private static void prepare(boolean quitAllowed) {

if (sThreadLocal.get() != null) {

throw new RuntimeException("Only one Looper may be created per thread");

}

sThreadLocal.set(new Looper(quitAllowed));

}

//返回与调用线程关联的实列

public static @Nullable Looper myLooper() {

return sThreadLocal.get();

}

静态工厂方法的两个缺点

1.只提供静态工厂方法的类,如果没有public或protected构造方法,将不能被继承

2.静态工厂方法不引人注目,容易被忽略,所以使用的时候最好遵守一些命名惯例

from, 接受单个参数 Date.from(instant);

of , 接收多个参数 Set 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 和上面一样,但这个保证能返回一个新的实例

Object newArray = Array.newInstance(classObject, arrayLen);

getType—和getInstance类似,之所以强调Type,是因为这个方法的返回类型不是调用这个方法的实例类型,比如调用类型File,返回类型FileStore。

FileStore fs = Files.getFileStore(path);

newType—和newInstance类似, BufferedReader br = Files.newBufferedReader(path);

type—getType and newType的简洁版, List litany = Collections.list(legacyLitany);

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。