zoukankan      html  css  js  c++  java
  • Java源码赏析(三)初识 String 类

    由于String类比较复杂,现在采用多篇幅来讲述

    这一期主要从String使用的关键字,实现的接口,属性以及覆盖的方法入手。省略了大部分的字符串操作,比如split()、trim()、replace()、contains()、matches()等。

    在《Java源码赏析(五)再识 String 类》中,会增加对String类中的字符串操作进行详细描述。

    今后,还会在《Java源码赏析(六)Java String 三顾》中介绍StringBuffer、StringBuilder两个类。

    /**
     * 精简的String结构,便于我们初步的理解, 省略了大部分构造方法和字符串操作
     * 使用了final关键字,说明此类是最终类,无法继承
     * 实现了序列化接口,排序接口,CharSequence接口
     */
    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
    
        private final char value[];
    
        private int hash; // Default to 0
    
        private static final long serialVersionUID =         -6849794470754667710L;
    
        /** 指明需要实例化的字段 */
        private static final ObjectStreamField[] serialPersistentFields =
            new ObjectStreamField[0];
    
        /** 省略CaseInsensitiveComparator()的实现,主要是用于按ASCII码的排序规则进行排序 */
        public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                             = new CaseInsensitiveComparator();
    
        /** 实现Comparable<String>,可用于集合类的排序功能 */
        public int compareTo(String anotherString) {
            int len1 = value.length;
            int len2 = anotherString.value.length;
            int lim = Math.min(len1, len2);
            char v1[] = value;
            char v2[] = anotherString.value;
    
            int k = 0;
            while (k < lim) {
                char c1 = v1[k];
                char c2 = v2[k];
                if (c1 != c2) {
                    return c1 - c2;
                }
                k++;
            }
            return len1 - len2;
        }
    
    
        /** 覆盖hashCode(),可以用于switch以及Map,Set的查询 */
        public int hashCode() {
            int h = hash;
            if (h == 0 && value.length > 0) {
                char val[] = value;
    
                for (int i = 0; i < value.length; i++) {
                    h = 31 * h + val[i];
                }
                hash = h;
            }
            return h;
        }
    
        /** 覆盖父类equal(),实现了值比较 */
        public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String)anObject;
                int n = value.length;
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                            return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }
    
        /** 覆盖父类toString() */
        public String toString() {
            return this;
        }
    
        /**
         *   实现CharSequence接口
         *   共有length(), charAt(int index), subSequence(int beginIndex, int endIndex) 等
         *   在实现subSequence()方法时使用了String中substring()方法
         */
    
        /** 获取字符串长度 */
        public int length() {
            return value.length;
        }
    
        /** 获取index位置的字符 */
        public char charAt(int index) {
            if ((index < 0) || (index >= value.length)) {
                throw new StringIndexOutOfBoundsException(index);
            }
            return value[index];
        }
    
        /** 获取字符串子串 */
        public CharSequence subSequence(int beginIndex, int endIndex) {
            return this.substring(beginIndex, endIndex);
        }
    
        
        /** 从索引位置beginIndex到endIndex处获取子串 */
        public String substring(int beginIndex, int endIndex) {
            if (beginIndex < 0) {
                throw new StringIndexOutOfBoundsException(beginIndex);
            }
            if (endIndex > value.length) {
                throw new StringIndexOutOfBoundsException(endIndex);
            }
            int subLen = endIndex - beginIndex;
            if (subLen < 0) {
                throw new StringIndexOutOfBoundsException(subLen);
            }
            return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen);
        }
    }
        /** 若不存在,将字符串存入常量池并返回在常量池的引用;若已存在,则直接返回字符串的引用 */
        public native String intern();

    阅读一个类的源码,首先要定性。

    1. 它是一个final的类,说明不可继承

    2. value为final,说明值创建后不可更改

    3. 所有看起来会修改String的方法都返回了一个新的String对象

    这种字符串的不可变性的好处在于简单(不用考虑并发问题),安全(不用考虑子类、值被修改等问题),高效(由于不可变可以设计常量池的处理)等。

    大概了解了String的属性和方法,我们回顾源码赏析一、二的内容,发现前两篇内容无一不体现在这个类中。希望大家可以结合前两篇来看待这个经典的类。

    Java源码赏析(一)Object 类

    Java源码赏析(二)Java常见接口


    一、Object中的重写方法 equals()、 hashCode()、 toString()

    二、常见的接口Serializable, Comparable的实现

    除了上面两点之外,还实现了CharSequence这个字符串的通用接口。StringBuffer、StringBuilder也实现了此接口。

    还有需要注意的一点是,字符串拥有 “操作符重载” ( +, +=)。我们可以方便的使用这个操作符进行一些处理。

    比如 连接字符串

    String a = "hello";
    String b = ", world";
    //输出 hello, world
    //
    System.out.println(a + b);

    注, “+” 最后不好放在for循环之中(第一种写法创建了100个对象),而第二种只创建了1个对象

    String s = new String();
    
    for(int i=0; i<100; i++) {
        s = s + i;
    }
    
    //等效于
    StringBuilder s1 = new StringBuilder();
    
    for(int i=0; i<100; i++) {
        StringBuilder one = new StringBuilder(i);
        s1.append(one).toString();
    }
    
    
    //高效写法
    StringBuilder s2 = new StringBuilder();
    
    for(int i=0; i<100; i++) {
        s2 = s2.append(i);
    }

    同理,频繁使用的String也可以直接写出 String s3 = "a";,不需要new出来 String s4 = new String("a");,这样能让这个值存在于常量池里(可以当成存在缓存)。

  • 相关阅读:
    数据的输入输出
    运算符和表达式
    深入理解Magento – 第三章 – 布局,块和模板
    压抑中......
    css控制图片自适应大小
    问来北京的追求是什么
    magento目录结构精编版
    无所事事的日子。
    jQuery实现等比例缩放大图片让大图片自适应页面布局
    MVC 小常识
  • 原文地址:https://www.cnblogs.com/kwanwoo/p/13667737.html
Copyright © 2011-2022 走看看