String源码分析(4)--浅析String中的静态工厂

本文基于JDK1.8

在方法篇中我们有对String类中的构造方法进行了一个分析,对于类而言,为了让客户端(即类的使用者)获取它自身的一个实例,除了上篇文章写的提供一个公有的构造器,还有一种管理对象创建的方法:类可以提供一个公有的静态工厂方法(static factory method),即一个返回类的实例的静态方法。

本篇文章将通过String中的valueOf()方法,谈一谈静态工厂方法的好处,目录如下:

  • valueOf()方法分析
  • (String)toStringvalueOf的区别
  • 静态工厂方法有什么好处?

valueOf( )方法分析

String中的valueOf()有多种重载形式。

Object对象与数据的重载:

String valueOf(Object obj);
String valueOf(char data[]);
String valueOf(char data[], int offset, int count);

6种基本类型的重载:

String valueOf(boolean b);
String valueOf(char c);
String valueOf(int i);
String valueOf(long l);
String valueOf(float f);
String valueOf(double d);

String类中除了各种形式的valueOf()的重载函数,还有一个copyValueOf()函数。看看它的实现:

public static String copyValueOf(char data[], int offset, int count) {
    return new String(data, offset, count);
}

public static String copyValueOf(char data[]) {
    return new String(data);
}

这两个函数是等同于

String valueOf(char data[], int offset, int count);
String valueOf(char data[]);

这两个函数的,那么当初为什么要设计这样两个copy函数呢?

在浅析String类的时候我们说过,JDK8的底层是由char[]实现的,从JDK9才变成了以byte[]来存储。而在早期的上述两个String构造器的实现中,是直接将参数的char[]数组作为String的value属性。如果作为参数的字符数组变化,将会导致String内容变化。

就像valueOf的源码的注释提到的:

The contents of the subarray are copied; subsequent modification of the character array does not affect the returned string.

字符数组的内容会被拷贝,字符数组中的子串的修改将不会影响返回的字符串。即以下情况修改data并不会影响s1与s2的值:

char[] data = "123456789";
String s1 = String.valueOf(data); // s1 = "123456789"
String s2 = String.copyValueOf(data); // s2 = "123456789"

data[0] = '9';

(String)、toString及valueOf的区别

在日常学习工作中,常常需要将对象转换成String方便打印调试等等,转String有三种方式:(String)objectobject.toString()以及String.valueOf(object)

那么那种方法更为好用呢?它们的区别又是什么呢?我们一起看一看。

强制类型转换(String)

所谓强制类型转换,就是将A类型对象套上一层B类型,将A类型对象当成B类型对象处理,这样可以调用B的方法,在编译过程中将不会报错。在强制转换之后你在IDE中的代码提示也能看到B类型特有的方法。但是在运行过程中,如果A不能转换成B,你调用了B对象的方法,就会报错。

就像你把石头当成救生圈,你调用石头的"沉没"功能运行没问题,一旦调用救生圈的"浮起"功能,就会报错。但是你把石头当成武器类型,调用"攻击"功能(如果JVM中能识别的话)就是ok的。

toString

我们知道Object类是所有类的父类,因此Java中的任意对象都可以调用toString()方法,如果在调用的类中没有重写toString()方法,将调用Object类中的toString

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

注意:调用的时候对象不能为null。

valueOf

从其源码中可以看出,它调用的仍然是toString()方法。

1public static String valueOf(Object obj) {
2    return (obj == null) ? "null" : obj.toString();
3}

但是你不需要担心对象是否为null了,如果为null,将返回"null"。

静态工厂方法有什么好处?

创建对象、获取实例时可以用静态工厂方法。比如Boolean类的简单示例:

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

注意,静态工厂方法与设计模式中的工厂方法模式不同。我们通过静态工厂方法来获取实例,而不是构造器,这样做具有几大优势:

静态工厂方法具有名称

当一个类重载了多个构造器时,复杂的参数列表我们构造起来比较麻烦,不够简洁。我们可以通过静态工厂方法,确切的描述正在被返回的对象,这种方法更加方便使用。

这种常常用在处理包含有多个,顺序也难记的构造器的类上。

不必每次调用时都创建一个新对象

使用预先创建好的实例对象,重复使用,这样有助于类总能严格控制在某个时刻哪些实例应该存在。这种类被称作实例受控的类(instance-controlled)。实例受控有几点好处:

  • 确保类是一个Singleton或者不可实例化。
  • 确保不可变类不会存在两个相等的实例。

单例好理解,那么什么叫不可实例化呢?有时候我们需要把一些代码拆出来放在公有类或者说工具类中,一般这种类里面都是静态方法,工具类的实例是没必要的,为了防止他人不小心实例化了这个类,我们把类的构造器设置为私有以强化其不可实例的特性。于静态工厂方法而言,我们可以这样写代码:

public static Animal getInstance() {
    throw new Exception....
}

如果是单例,则返回已经预构建的对象,如果是不可实例化,则抛出异常,
除此之外,不可变类--成员变量都是不可变的类 可以确保不会有两个相等的实例。

可以返回原返回类型的任何子类型的对象

比如上述代码中的getInstance(),我们可以返回猫,狗。

创建参数化类型实例的时候,它们使代码变得更加简洁。

这一条其实在JDK7以及被优化过了。主要就是针对

Map<String, List<List<String>> > m = new HashMap<String, List<List<String>>>();

这种类型参数比较冗长的代码。通过静态工厂方法,比如:

public static <K, V> HashMap<K, V> newInstance() {
    return new HashMap<K, V>();
}

就可以让代码更加简洁。

静态工厂方法当然有一些坏处,这里就不一一细表了,感兴趣的同学可以去看看Effective Java的第一条目,讲的就是静态工厂方法。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容