[置顶] 学习JDK源码:编程习惯和设计模式
编程习惯
1、用工厂方法替代构造函数
Boolean.valueOf()
通过一个boolean简单类型,构造Boolean对象引用。
优点:无需每次被调用时都创建一个新对象。同时使得类可以严格控制在哪个时刻有哪些实例存在 >>实例受控的类
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE;
}
静态工厂方法Boolean.valueOf(String)几乎总是比构造函数Boolean(String)更可取。构造函数每次被调用时都会创建一个新对象,而静态工厂方法则从来不要求这样做,实际上也不会这么做。
BigInteger.probablePrime()
构造方法BigInteger(int, int, Random)返回一个可能为素数的BigInteger,而用一个名为BigInteger.probablePrime()的静态工厂方法就更好。(JDK1.4最终增加了这个方法。)
优点:方法名对客户端更友好
public class BigInteger extends Number implements Comparable<BigInteger> {
public static BigInteger probablePrime(int bitLength, Random rnd) {
if (bitLength < 2)
throw new ArithmeticException("bitLength < 2");
// The cutoff of 95 was chosen empirically for best performance
return (bitLength < SMALL_PRIME_THRESHOLD ?
smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));
}
EnumSet
JDK1.5引入的java.util.EnumSet类没有public构造函数,只有静态工厂方法。根据底层枚举类型的大小,这些工厂方法可以返回两种实现:
如果拥有64个或更少的元素(大多数枚举类型都是这样),静态工厂方法返回一个RegularEnumSet实例,用单个long来支持;
如果枚举类型拥有65个或更多的元素,静态工厂方法则返回JumboEnumSet实例,用long数组来支持。
优点:静态工厂方法能返回任意子类型的对象。可以根据参数的不同,而返回不同的类型。
/**
* Creates an empty enum set with the specified element type.
*
* @param elementType the class object of the element type for this enum set
* @throws NullPointerException if <tt>elementType</tt> is null
*/
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable
{
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
Enum[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum"); if (universe.length <= 64)
return new RegularEnumSet<E>(elementType, universe);
else
return new JumboEnumSet<E>(elementType, universe);
}
} class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
}
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
}
Collections.unmodifiableMap(Map)
Java集合框架中有32个集合接口的便利实现,提供不可修改的集合、同步集合等等。几乎所有的实现都通过一个不可实例化类(java.util.Collections)中的静态工厂方法导出,返回对象的类都是非public的。
优点:静态工厂方法能返回任意子类型的对象。可以返回一个对象而无需使相应的类public。用这种方式隐藏实现类能够产生一个非常紧凑的API
public class Collections {
public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
return new UnmodifiableMap<K,V>(m);
}
private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {
}
}
2、私有化构造函数,使类不能被子类化
Arrays
这种工具类设计出来并不是为了实例化它。然而,如果不显式地编写构造函数,编译器则会提供一个公共的无参数的默认构造方法。
所以将构造函数私有化:
public class Arrays {
// Suppresses default constructor, ensuring non-instantiability.
private Arrays() {
}
}
当然,还可以在这个私有构造器内部加上 throw new AssertionError(),可以确保该方法不会再类内部被意外调用
这种习惯用法的副作用是类不能被子类化了。子类的所有构造函数必须首先隐式或显式地调用父类构造函数,而在这种用法下,子类就没有可访问的父类构造函数可调用了。
3、避免创建不必要的对象
Map.keySet()
Map接口的keySet()方法返回Map对象的一个Set视图,包含该Map的所有key。
看起来好像每次调用keySet()都需要创建一个新的Set实例。而实际上,虽然返回的Set通常是可变的,但返回的对象在功能上是等同的:如果其中一个返回对象改变,其他对象也会改变,因为他们的底层都是同一个Map实例。虽然创建多个KeySet视图对象并没有害处,但也没有必要。
public abstract class AbstractMap<K,V> implements Map<K,V>
transient volatile Set<K> keySet = null; // volatile!!
public Set<K> keySet() {
if (keySet == null) {
keySet = new AbstractSet<K>() {
。。。
};
}
return keySet;
}
}
4、消除无用的对象引用
LinkedHashMap.removeEldestEntry()
缓存实体的生命周期不容易确定,随着时间推移,实体的价值越来越低。在这种情况下,缓存应该不定期地清理无用的实体。可以通过一个后台线程来清理(可能是Timer或ScheduledThreadPoolExecutor),也可以在给缓存添加新实体时进行清理。
LikedHashMap可利用其removeEldestEntry,删除较老的实体:
public class LinkedHashMap...{
void addEntry(int hash, K key, V value, int bucketIndex) {
createEntry(hash, key, value, bucketIndex);
// Remove eldest entry if instructed, else grow capacity if appropriate
Entry<K,V> eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
} else {
if (size >= threshold)
resize(2 * table.length);
}
}
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
}
——可以继承LinkedHashMap,覆盖其removeEldestEntry方法。
注:如果想要缓存中的对象只要不被引用,就自动清理;则可以用WeakHashMap
5、如果指定了toString返回值的格式,则应该提供一个对应的静态工厂方法或构造函数
BigInteger.toString()
/**
* Returns the String representation of this BigInteger in the
* given radix. If the radix is outside the range from {@link
* Character#MIN_RADIX} to {@link Character#MAX_RADIX} inclusive,
* it will default to 10 (as is the case for
* {@code Integer.toString}). The digit-to-character mapping
* provided by {@code Character.forDigit} is used, and a minus
* sign is prepended if appropriate. (This representation is
* compatible with the {@link #BigInteger(String, int) (String,
* int)} constructor.)
*
* @param radix radix of the String representation.
* @return String representation of this BigInteger in the given radix.
* @see Integer#toString
* @see Character#forDigit
* @see #BigInteger(java.lang.String, int)
*/
public String toString(int radix) { } /**
* Returns the decimal String representation of this BigInteger.
* The digit-to-character mapping provided by
* {@code Character.forDigit} is used, and a minus sign is
* prepended if appropriate. (This representation is compatible
* with the {@link #BigInteger(String) (String)} constructor, and
* allows for String concatenation with Java's + operator.)
*
* @return decimal String representation of this BigInteger.
* @see Character#forDigit
* @see #BigInteger(java.lang.String)
*/
public String toString() {
return toString(10);
}
对应的构造函数如下。这样程序员能容易地在对象及其字符串表示之间来回转换
/**
* Translates the decimal String representation of a BigInteger into a
* BigInteger. The String representation consists of an optional minus
* sign followed by a sequence of one or more decimal digits. The
* character-to-digit mapping is provided by {@code Character.digit}.
* The String may not contain any extraneous characters (whitespace, for
* example).
*
* @param val decimal String representation of BigInteger.
* @throws NumberFormatException {@code val} is not a valid representation
* of a BigInteger.
* @see Character#digit
*/
public BigInteger(String val) {
this(val, 10);
}
/**
* Translates the String representation of a BigInteger in the specified
* radix into a BigInteger. The String representation consists of an
* optional minus sign followed by a sequence of one or more digits in the
* specified radix. The character-to-digit mapping is provided by
* {@code Character.digit}. The String may not contain any extraneous
* characters (whitespace, for example).
*
* @param val String representation of BigInteger.
* @param radix radix to be used in interpreting {@code val}.
* @throws NumberFormatException {@code val} is not a valid representation
* of a BigInteger in the specified radix, or {@code radix} is
* outside the range from {@link Character#MIN_RADIX} to
* {@link Character#MAX_RADIX}, inclusive.
* @see Character#digit
*/
public BigInteger(String val, int radix) {}
迭代器模式
1、Collection.iterator()
未完待续。。
[置顶] 学习JDK源码:编程习惯和设计模式的更多相关文章
- [置顶] 学习JDK源码:可进一步优化的代码
1.参数化类型的构造函数比较啰嗦 new HashMap<String, List<String>>() 如果你调用参数化类的构造函数,那么很不幸,你必须要指定类型参数,即便上 ...
- 深入学习JDK源码系列之、ArrayList
前言 JDK源码解析系列文章,都是基于JDK8分析的,虽然JDK15马上要出来了,但是JDK8我还不会,我... 类图 实现了RandomAccess接口,可以随机访问 实现了Cloneable接口, ...
- 学习JDK源码(二):Integer
最近没有好好保持学习的好习惯,该打. 天天忙,感觉都不知道在干嘛.真的厌倦了普通的Java代码,还是想学点新技术. 用了这么久的Java,最常用的数据类型肯定是Int了,而他的包装类Integer用的 ...
- 学习JDK源码(一):String
用了好久的Java了,从来没有看过jdk的源码,趁着今天有点时间,拿出了jdk的源码看了下,今天先看了关于String的,毕竟开发中String类型使用最广泛.在我们下载安装jdk的时候,部分源码也已 ...
- [置顶] Cocos2d-x 实例源码分析之二 小实例的主框架
这篇文章是分析第一个小实例ActionTest的源码.其实所有实例程序的结构都是一样的,只有特定方法里的代码不同,大的框架都是一样的.也就是说看完这篇文章你就可以自己开始分析其他源码了. 废话不多说, ...
- 【设计模式】JDK源码中用到的设计模式
https://blog.csdn.net/angjunqiang/article/details/42061453 https://blog.csdn.net/baiye_xing/article/ ...
- JDK源码中使用的设计模式
结构型模式: 适配器模式: 用来把一个接口转化成另一个接口. java.util.Arrays#asList() javax.swing.JTable(TableModel) java.io.Inpu ...
- JDK源码学习笔记——String
1.学习jdk源码,从以下几个方面入手: 类定义(继承,实现接口等) 全局变量 方法 内部类 2.hashCode private int hash; public int hashCode() { ...
- JDK源码系列总索引
一 目标 记录学习jdk源码的一些笔记和心得,jdk版本使用11.0.1,工具idea Class后面序号为优先级1-4,优先级递减 目录转载自博客: https://blog.csdn.net/qq ...
随机推荐
- Spring + Spring MVC + Hibernate
Spring + Spring MVC + Hibernate项目开发集成(注解) Posted on 2015-05-09 11:58 沐浴未来的我和你 阅读(307) 评论(0) 编辑 收藏 在自 ...
- Linux_下安装MySQL
linux下mysql 最新版安装图解教程 1.查看当前安装的linux版本 命令:lsb_release -a 如下图所示 通过上图中的数据可以看出安装的版本为RedHat5.4,所以我们需要下载R ...
- Oracle 11g 环境,使用utl_smtp创建一个存储过程来发送邮件
太多的在线电子邮件存储过程.我不转发,弄个作为一个简单的例子演示. create or replace procedure Send_mail(mail_body varchar2) is smtp_ ...
- 基于Hama并联平台Finding a Maximal Independent Set 设计与实现算法
笔者:白松 NPU学生. 转载请注明出处:http://blog.csdn.net/xin_jmail/article/details/32101483. 本文參加了2014年CSDN博文大赛,假设您 ...
- file 上传文件后缀名 限制
比如: 要求只能上传Excel <input type="file" accept="application/vnd.ms-excel,application/vn ...
- Windows 10技术布局,谈微软王者归来
Windows 10技术布局,谈微软王者归来 每个时代都有王者,王者的成功,往往是因为恰逢其时地发布了一个成功的产品(具有里程碑意义,划时代的产品).Windows 95的成功标示着微软是PC时代的王 ...
- Codeforces 437D The Child and Zoo(贪心+并查集)
题目链接:Codeforces 437D The Child and Zoo 题目大意:小孩子去參观动物园,动物园分非常多个区,每一个区有若干种动物,拥有的动物种数作为该区的权值.然后有m条路,每条路 ...
- Oracle / PLSQL写语句的时候常使用的函数
最近在学习数据库方面的知识,做个标记. 这里有英文解释,建议多看看英文文档: https://www.techonthenet.com/oracle/functions/ 下面开始记录一下,自己在Or ...
- 谢绝艳照门 - 手把手教你把当今很hit的家庭监控IP Camera变得网络安全起来
IP Camerars现在已经越来越便宜了,很多人都可以买得起,并且大家也乐意去购买,因为它们的确是用来监控你在高房价的中国购买的爱巢的非常便利的设备.当然,配套的监控应用也层出不穷,从通用的家庭安全 ...
- 优秀个人免费私有云OwnCloud 8.0终于发布 - 亮眼新功能初探简介
OwnCloud是一个基于Linux的私有云开源项目,用户可以免费使用它来搭建自己的私有云来进行文件和多媒体等的分享. 本人有幸在大概一年多前因为项目需要而接触和使用到OwnCloud,但不幸的是当时 ...