0002JDK源码分析之Appendable接口家族
Posted Java框架源码分析
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了0002JDK源码分析之Appendable接口家族相关的知识,希望对你有一定的参考价值。
本文将介绍java.lang包下的常用接口和类,接口分别是Appendable、Serializable、CharSequence以及Comparable,类分别是String、StringBuffer、StringBuilder以及AbstractStringBuilder。提示:Serializable位于java.io包。
本文大纲:
一、继承体系图
二、接口的职责
三、类的源码分析
一、继承体系图
二、接口的职责
1、Appendable接口的职责
Appendable的意思是可追加的,该接口提供可追加char序列的操作,声明了三个抽象方法,声明的方法的返回值都是自身对象,这是一种链式编程的方法定义,使用者可以直接通过.的方式进行调用(联想一下StringBuffer),在代码层面显得十分简洁。拓展一点,大家在定义一些类的时候,如果要实现不断的往类内某个属性追加内容或值,可以使用这种方式。声明的抽象方法如下图所示:
Appendable append(CharSequence csq) throws IOException; Appendable append(CharSequence csq, int start, int end) throws IOException; Appendable append(char c) throws IOException; |
2、Serializable接口的职责
序列化接口,如果一个类要序列化,就要实现这个接口,具有序列化和反序列化的功能。
3、CharSequence接口的职责
CharSequence是char
值的一个可读序列。其子类有StringBuffer、StringBuilder、String等类。
4、Comparable接口的职责
可比较的,Comparable接口主要用于比较两个对象大小实现排序,实现该接口的类需要实现其抽象方法:public intcompareTo(T o);
三、类的源码分析
1、AbstractStringBuilder抽象类
AbstractStringBuilder类是一个抽象类,子类有StringBuffer和StringBuilder,该类主要操作char数组进行追加或插入字符序列。
重要属性描述:
char value[]; //保存字符序列
int count; //字符序列的实际长度
这是一个可变序列,其默认容量由子类确定,当追加字符序列的时候,会自动扩容,每次+1再翻倍。扩容的方法如下:
void expandCapacity(int minimumCapacity) { int newCapacity = (value.length + 1) * 2; if (newCapacity < 0) { newCapacity = Integer.MAX_VALUE; } else if (minimumCapacity > newCapacity){ newCapacity = minimumCapacity; } value = Arrays.copyOf(value,newCapacity); } |
2、StringBuilder类
StringBuilder类继承AbstractStringBuilder抽象类,一个可变的字符序列,主要是对父类的方法进行重写,使其方法返回StringBuilder自身对象,而不是AbstractStringBuilder对象。这是一个对StringBuffer类的简单替换,用于单线程,性能优于StringBuffer。StringBuilder类的内部实现很简单,引人注目的是该类是可序列化的,实现了序列化接口,并提供了如下两个私有方法:
static final long serialVersionUID = 4383685877147921099L; private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); s.writeInt(count); s.writeObject(value); } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); count =s.readInt(); value = (char[])s.readObject(); } |
让人思考的是,这两个私有方法和一个序列化号是如何实现序列化的?回想一下序列化的过程,首先是序列化,毋庸置疑,序列化调用的是writeObject方法,参数是一个对象输出流,应该是写到文件或内存,私有的方法被调用肯定要通过反射,那私有的方法是如何被反射调用的呢?其次,就是反序列化,调用的自然是readObject私有方法,参数是一个对象输入流。序列化号是一个对象序列化的标识,标记着某个对象,用于反序列化时根据这个标识找到确切的对象。对于这个具体的对象序列化过程,我会单独撰文编写案例说明。
3、StringBuffer类
StringBuffer类继承AbstractStringBuilder抽象类,也是一个可变的字符序列,主要是对父类的方法进行重写,并对数据操作实现同步,因此该类是线程安全的,实现同步的策略是使用synchronized关键字,其源码中大量方法都是同步方法。StringBuffer类也是可序列化的,实现了序列化接口,也有私有的对象序列化和反序列化方法,实现原理和StringBuilder差不多。
4、String类
String类也是一个操作字符序列的类,这是我们开发使用最多的类了。这个类与StringBuffer、StringBuilder不同的是该类是不可变的,也就说你每次创建new对象的时候都会得到一个新的对象,但是String类使用了字符池来管理字符序列,所以不会重复创建对象,这是如何实现的呢?
源码中只有这么一行代码:
public native String intern();
该方法是字符池使用的,用于比较两个对象是否相等,如果相等则代表池中含有该对象,直接返回。如果不相等则代表该对象不存在于池中,创建这个对象并放进池中。对于池的内容,后期会有单独的文章介绍,在这只是简单阐述一下。
String类有一个内部类CaseInsensitiveComparator,实现忽略大小写比较功能,代码如下:
private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable { // use serialVersionUIDfrom JDK 1.2.2 for interoperability private static finallong serialVersionUID = 8575799808933029326L; public intcompare(String s1, String s2) { intn1=s1.length(), n2=s2.length(); for (int i1=0,i2=0; i1<n1 && i2<n2; i1++, i2++) { char c1 =s1.charAt(i1); char c2 =s2.charAt(i2); if (c1 != c2) { c1 =Character.toUpperCase(c1); c2 =Character.toUpperCase(c2); if (c1!= c2) { c1= Character.toLowerCase(c1); c2= Character.toLowerCase(c2); if(c1 != c2) { return c1 - c2; } } } } return n1 -n2; } } |
String类还涉及到模式匹配,格式化等内容,这些将在java.util包的时候详细介绍。比如:Pattern类、Matcher类、Formatter类等。
四、总结
本文主要介绍了一些操作字符序列的常用类,String、StringBuffer、StringBuilder,这些都是开发者经常使用到的类,了解其原理以及实现,有利于我们更好的开发。
以上是关于0002JDK源码分析之Appendable接口家族的主要内容,如果未能解决你的问题,请参考以下文章