[置顶] 学习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 ...
随机推荐
- crawler_http关闭连接
1:ps aux|grep Spider4Test.jar 查看端口 2: lsof -p [端口号] 在爬虫运行期间如果看到 大量的 TIME_WAIT WAIT_CLOSE 说明请求关闭阻塞[ ...
- DP 水的问题
假设的自然数N的K随机二进制表示是不相邻的两个相邻的数字.那么我们说这个数字是K好一些. 乞讨L地点K十六进制数K的相当数量的数. 例如K = 4.L = 2什么时候.整个K好一些11.13.20.2 ...
- CSharp设计模式读书笔记(20):观察者模式(学习难度:★★★☆☆,使用频率:★★★★★)
观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新.观察者模式的别名包括发布-订阅(Publish/ ...
- order by使用方法
1.ORDER BY 中关于NULL的处理 缺省处理,Oracle在Order by 时觉得null是最大值,所以假设是ASC升序则排在最后,DESC降序则排在最前. 当然,你也能够使用nulls f ...
- Android 2.3.5源码 更新至android 4.4,能够下载,度娘网盘
Android 4.4源代码下载(linux合并) ==============================切割线结束========================= 旧版本号的能够使用115, ...
- Java数据结构与算法(1) - ch02有序表(OrderedArray)
有序表需要掌握的插入方法,删除方法和二分法查找方法. 插入方法: 从前往后找到比要插入的值大的数组项,将该数组项及之后的项均后移一位(从最后一项起依次后移),最后将要插入的值插入当前数组项. 删除方法 ...
- struts2的Action该方法不能去
最近做的一个特征,使用struts2,input标签内容,并与相应的内容背景的实体类,当提交方法,无法进入action该方法和程序没有报错被,检验N通方法还没有找到,查找终于找到了,它是input标签 ...
- std::move()
#include <iostream> #include <utility> #include <vector> #include <string> i ...
- JavaScript实现简单日历
页面代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w ...
- iptables的配置文件/etc/sysconfig/iptables不存在怎么办
iptables的配置文件/etc/sysconfig/iptables不存在怎么办 首先要看一下iptables是否安装了,使用service iptables status或yum info ip ...