【小白的java成长系列】——String类的深入分析(基于源码)
接着前面面向对象来说吧~今天来说说String类。。其实String类也包含很多面向对象的知识的~
首先来问一个问题:我们在开发过程中,如果要使用一个类的话,就要创建对象,这句话没什么问题吧~在实际开发的时候确实是这样的,只有创建了对象才能真正的去使用一个普通的类,我们一般创建对象,几乎所有的类创建对象都是要通过new关键字来创建的~
问题就来了。。为什么我们的String可以直接写成String str = "abc";这样子呢?
当然String类也可以通过new来创建对象的。。。
其实也不难,我们看到它的源码说明就知道的:
* Strings are constant; their values cannot be changed after they * are created. String buffers support mutable strings. * Because String objects are immutable they can be shared. For example: * <p><blockquote><pre> * String str = "abc"; * </pre></blockquote><p> * is equivalent to: * <p><blockquote><pre> * char data[] = {'a', 'b', 'c'}; * String str = new String(data); * </pre></blockquote><p>
进入String的源码,最前面就能看到上面的文字的:大致的意思是,String的对象值其实是通过char[]数组来存储的,String str = "abc";等同于char data[] = {‘a‘, ‘b‘, ‘c‘}; String str = new String(data);明白清晰了吧~
1、String类的定义:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence
问题:在开发过程中,我们可以继承String类吗?
答案:不行的,我们看定义就知道,String的定义使用了final修饰符,定义为了终结类,所以String是不能做扩展的。
implements:这个关键字是用来表示实现接口作用的,意思就是Serializable、Comparable和CharSequence都是接口的。
查看接口源码:
Comparable<T> :表示比较器作用,<T>采用了java泛型的形式
Serializable:
public interface Serializable { }
我们可以看到Serializable接口里面啥都木有,那为什么我们要实现这个接口呢?这个接口的作用是啥呢?
作用:java类的序列化,至于序列化,后面会详细介绍。其实Serializable是java的一个标记接口,什么叫标记接口?Serializable只是作为一个标记的作用,关于它具体的功能和作用交给了JVM底层去实现了,实现了这个接口,只是通知JVM,String这个类可以序列化。
CharSequence:表示字符序列吧~这个没啥好说的,String的存储方式依赖于字符序列的~
2、属性
private final char value[]; //String值就是存储在value[]上的 private int hash; // Default to 0 表示hash值, private static final long serialVersionUID = -6849794470754667710L;//序列化作用 private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];//序列化作用
我们只要了解String类的属性就可以,几乎都不会用到的,因为都是定义成了private,私有化了~
3、构造方法这里也只说几个特殊的,一般在开发过程中也不会用到构造方法的,因为很少使用new来创建String对象的,都是直接使用String str = "abc";这样子的形式。。
在面试过程中,很多面试官会问到String str = new String("abc");这个创建了几个对象?至于答案和解释,这边就不做介绍了,想知道的就去网上查找了解~这个涉及到底层的内存问题的,描述起来篇幅会很长的~
public String(String original) { this.value = original.value; this.hash = original.hash; }从上面可以看到,String两个核心就是value和hash的,这两个值基本决定了String对象的。
public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }这个是通过底层数组拷贝的方式创建,其实底层使用的是System.arrayCopy()这个方法,此方法使用了native修饰的,底层是由C/C++来实现的,其实就是一个拷贝的作用。
public String(byte bytes[], int offset, int length) { checkBounds(bytes, offset, length); this.value = StringCoding.decode(bytes, offset, length); }这个表示的是通过字节(byte)来构造字符串,其实底层的实现也是通过System.arrayCopy()这个方法的。
其他的基本也没什么好说的,了解一下就可以的。我们可以看到有些构造使用了@Deprecated注解,这个注解表示的过时,不推荐使用这个方法的。
4、常用方法
public int length() { //返回字符串长度 return value.length; } public boolean isEmpty() {//判断字符串是不是为空 return value.length == 0; } public char charAt(int index) {//字符串中的某个字符,index表示字符的位置 if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; } public byte[] getBytes() {//获取字节数组 return StringCoding.encode(value, 0, value.length); } public boolean equals(Object anObject) {//字符串比较,我们知道基本类型的比较都是通过==来做比较的, //但是字符串需要使用此方法来做比较的
我们主要来验证一下==和equals方法
package me.javen.oop; public class StringDemo { public static void main(String[] args) { String str1 = "hello" ; // 直接赋值 String str2 = new String("hello") ; // 通过new赋值 String str3 = str2 ; // 传递引用 System.out.println("str1 == str2 --> " + (str1==str2)) ; // false System.out.println("str1 == str3 --> " + (str1==str3)) ; // false System.out.println("str2 == str3 --> " + (str2==str3)) ; // true //以下通过equals方法 System.out.println("str1 equals str2 --> " + (str1.equals(str2))) ; // true System.out.println("str1 equals str3 --> " + (str1.equals(str3))) ; // true System.out.println("str2 equals str3 --> " + (str2.equals(str3))) ; // true } }此外还有一个比较方法也用得比较多:
public boolean equalsIgnoreCase(String anotherString) {//不分大小写比较
public boolean startsWith(String prefix) {//判断字符串是不是以prefix开头 public boolean endsWith(String suffix) {//判断字符串是不是以suffix结尾 public int hashCode() {//获取字符串的hash值 public int indexOf(String str) {//获取字符str的起始位置,-1表示没有这个字符 return indexOf(str, 0); } public String substring(int beginIndex, int endIndex) {//截取字符串beginIndex表示起始位置,endIndex表示结束位置 public String replaceAll(String regex, String replacement) {//字符串替换replacement替换regex public String[] split(String regex) {//分隔字符串,regex表示分隔符 public String toLowerCase() {//将字符串全部转换为小写 public String toUpperCase() {//将字符串全部转换为大写 public String trim() {//去掉首尾空格,字符中间的空格不能去掉 public static String valueOf(Object obj) {//将obj转换成字符串,这个可以传递任意类型,比如数字,字符,浮点数等等
此外还有其他的很多方法,这边就不列举出了,学习者可以通过代码的方式去使用这些个方法,列举出来的表示开发中常用的方法~
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。