小白白让你懂之Java String类详解(一)
对于java的学习,String类是一个重点,初学java,我们可能对于String类的认知也就在以下几点上吧:
(1)new String()可以获得一个字符串的引用地址
(2)String str=”abc”,也可以直接给String变量提供字符串的常量值。
(3)String a=new String(“123”)
String b=new String(“123”);
System.out.println(a==b);//false
System.out.println(a.equals(b))//true
(4)String类的一些操作方法:trim()、replace()、substring()等。
但java 是一个面向对象的语言,要学好面向对象,是不是更好地以java的这些类的设计思路上去体会和学习面向对象的精妙之处呢。
下面让我们从不断提出问题到API中和源码中去获取到相关内容。
我们先看API:
可以得到的信息有:
String的类是从java.lang包中得到的
实现了三个接口:
Serializable,CharSequence,Comparable<String>
我们先分别看这个接口实现后会出现什么样的情况。
假使我们自己写了一下Strings的类。
先实现Serializalbe接口:
实现后发现这个接口不用重写任何方法,F3查看Serializable的源文件:
看到其实它里面什么也没写,如果了解序列化会知道,这也许就是一个标志,不实现这个接口还做不了序列化。
好了,第一个接口实际上是个标志。
我们再看第二个接口:
CharSequence
实现后发现必写3个方法。其中就有String类我们熟悉的length()和charAt方法
所以与其说String类有长度的length()方法,不如说是CharSequence这个接口规范String必须有一个length方法,这样我们就可以理解API中的下面的内容。
等效的这个char数组,应该有长度,而java数组的长度length是属性,String length()是方法,这个是CharSequence规范String必须完成的内容。当然也有一些好处,我们在后面会提到。
然后我们再实现第三个接口,Comparable<String>来看一下效果:
我们又看到了实现的方法compareTo(),这个也是String API中的比较方法.可见Comparable<String>规范了CompareTo这个方法。
其它的String API中的方法应该是String特有的方法,就是对字符串进行一系列的增、删、改、查。
好了,那么我们看API上面介绍String的第一句话:
以上是API 中的描述,字符串是一个常量,为什么,我们都知道常量是由final这个关键字来修饰的变量。我们看一下String的源文件。
可以看到前面的部分有一个fina char[]型的数组,而API下面介绍的内容也就成立了。
也就是说new String就相当于把String参数中的字符数组赋给了String当中的value;
我们在String源文件中也看到了这样的构造器:
调用了Arrays的copyof复制了一个这样的char型数组,而数组的来源恰恰就是value;
我们根据这样的方法就仿一个String类
步骤是:
(1)我们自己定义Strings
(2)让他单独实现CharSequence;
(3)定义一个常量char[] value;
(4)构造器中用Arrays的copyof方法拷贝Strings传过来的字符数组。
(5)把实现CharSequence 必须让我们实现的方法length(),用数组的length属性返回
(6)把实现CharSequence 必须让我们实现的方法CharAt,用数组的下标值返回
这样,我们得到的Strings的代码就是
这就相当于我们实现了一个简单的String类.
我们可以在主程序中调用一下:
在Strings里面有一个value就是我们的char数组;
既然Strings是个字符数组,我们就可以对里面的value成员变量进行遍历;
执行的结果就是:
abcde
那么String类是不是如此呢?
我们把Strings改成String,发现str.value报错
为什么呢?
从源码上看,这个变量被private了,实现了面向对象对成员变量的封装,但没有提供getter和setter方法,让我们使用这个量,这就是为什么String实际是一个char数组,但不能被我们直接遍历,因为成员变量被private私有化了。当我们在进行面向对象编程时,也可以学习这种方法,把一个成员变量封装后,不提供开放的方法,提供这个私有化成员的增、删、改、查方法。
然后我们看后面任意的String方法,都是对这个value进行操作.
例如substring
这里面的new Strings(this.value,start,len)是重载的构造方法,一样利 用了Arrays的工具类:
我们可以看到上述代码的Arrays.copyOfRange一样是复制了一个数组,产生另外的堆空间地址存放这个子字符串。
这样我们就构建了自己的Strings类。
我们把value的public改成private也就跟 String类没有什么差别了。
我们也理解了String类的面向对象的思维:
(1)String就是一个char数组.
(2)在String类里value成员变量中存放着这个char数组。
(3)成员变量value私有化,不提供直接的遍历和操作,我们只能借助于String类提供的方法来对value进行相关的增、删、改、查。
紧接着,我们看一下这样的一个程序段:
传入的这些\u的数据是十六进制数,也就是两个字节拼接出的\u后面的内容,这些就是unicode编码。
控制台的输出:
看到这些unicode代码是汉字。
其实unicode编码就是char数组里面存放的内容.
所以String就是一个存放unicode编码的char型数组。