zoukankan      html  css  js  c++  java
  • String底层解析

    目录

    关于String

    String类型的底层代码是Java所有底层代码中相对来说比较简单、好理解。同时,String底层的源码又是面试官经典的“面试第一题”。“良好的开端就是成功的一半”,因此这个问题回答的好坏会很大程度影响你接下来的面试。我会在这篇博客中梳理几个面试中频率较高的知识点。

    String内部结构

    String内部存储结构为char数组,有两个私有变量,一个是char[],哈希值。
    具体结构:

     class String implements Serializable,Comparable<String>,CharSequence {
             //用于存储字符串的值
           private char value[];
              //缓字符串的hash code
           private int hash;
    }
    

    String的构造方法

    String的构造方法有四个,前两个比较常见,参数是String字符串和char[]数组。
    后两个是容易被忽略的小透明,参数是StringBuffer和StringBuilder

    1.String为参数的构造方法

    //String为参数的构造方法
          public String(String original){
              this.value = original.value;
              this.hash = original.hash;
         }
    

    2.char[] 为参数的构造方法

    //char[]为参数的构造方法
          public String(char value[]){
             this.value = Arrays.copyOf(value,value.length);
          }
    

    3.StringBuffer为参数的构造方法

    //StringBuffer为参数的构造方法
          public String(StringBuffer buffer){
              synchronized(buffer){
                  this.value=Array.copyOf(buffer.getValue(),buffer.length())
              }
          }
    

    4.StringBuilder为参数的构造方法

    //StirngBuilder为参数的构造方法
          public String(StringBuilder builder){
               this.value = Arrays.copyOf(builder.getValue(),builder.length());
          }
    

    String中的对比——equals()和compareTo()的对比

    equals()方法

    String中的equals()方法是重写了Object类中的equals()方法,其本质是利用了“==”。

    equals()方法先检验对比双方的引用地址是否相等(“==”),如果地址相等,对比双方自然相等,返回true。然后检验需要对比的对象是否为String类型(“instanceof”),如果不是则返回false。之后对比两个字符串的长度是否对等(“==”),最后将两个字符串都转化为char[]形式,循环对比每一个字符。

    源码:

    public boolean equals(Object anObject){
               //对象引用相同直接返回true
               if(this==anObject){
                   return true;
               }
              //判断需要对比的值是否为String类型,如果不是则返回false
               if(anObject instanceof String){
                   String anotherString = (String)anObject;
                   int n = value.length;
                   if(n==anotherString.value.length){
                       //把两个字符串都转化为char数组对比
                       char v1[]=value;
                       char v2[]=anotherString.value;
                       int i=0;
                       //循环比对两个字符串的每一个字符
                       while(n--!=0){
                           //如果其中有一个字符不相等就true false,否则继续对比
                           if(v1[i]!=v2[i])
                               return false;
                           i++;
                       }
                       return true;
                   }
               }
              return false;
          }
    

    compareTo()方法

    compareTo()方法不涉及地址的对比,它只是循环比较所有的字符串。当两个字符串中有任意一个字符不相同的时候,返回两个字符的差值。如果长度不对等则返回两个字符串长度的差值。

    源码:

    public int compareTo(String anotherString){
               int len1 = value.length;
               int len2 = anotherString.value.length;
               //获取到两个字符串长度最短的那个int值
               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;
          }
    

    小结:String中compareTo()和equals()方法的异同点

    不同点:

    • equals()可以接收一个Object类型的参数,而compareTo()只能接收String类型的参数
    • equals()返回值为Boolean,而compareTo()的返回值则为int

    相同点:

    • 两者都可以用于两个字符串的比较。当equals()方法返回true时,或是compareTo()方法返回0时,则表示两个字符串完全相同

    String的常用方法清单

    • indexOf():查询字符串首次出现的下标位置
    • lastIndexOf():查询字符串最后出现的下标位置
    • contains(): 查询字符串中是否包含另一个字符串
    • toLowerCase(): 把字符串全部转换成小写
    • toUpperCase(): 把字符串全部转换成大写
    • length(): 查询字符串的长度
    • trim(): 去掉字符串首尾空格
    • replace():替换字符串中的某些字符
    • split(): 把字符串分割并返回字符串数组
    • join(): 把字符串数组转为字符串

    关于equals()方法:“==”和equals()的区别?

    “==”:

    • 对于基本数据类型来说,是比较两者的是否相等
    • 对于引用数据类型来说,是用于比较两者引用地址是否相等

    equals():

    • String类型的equals()是重写了Object类中的equals()方法,他的基本实现是靠的“==”

    Object类中的equal方法:

    public boolean equals(Object obj){
                   return (this==obj);
               }
    

    为什么用final修饰String类?

    对于这个问题,Java之父James Gosling在一次记者采访中说明过,大体的原因如下:

    1.安全
    迫使String类被设计成不可变类的一个原因就是安全。(在进行系统的校验工作中,如果设为可变类,就有可能会出现严重的系统崩溃问题。)

    举例:字符串常量池

    2.高效
    高司令是这样回答的:他会更倾向于使用不可变类(final),因为它能够缓存结果,当你在传参时不需要考虑谁会修改它的值。如果是可变类的话,则有可能需要重新拷贝出来一个新值进行传参,这样性能上就会有一定的损失。

    String和StringBuilder、StringBuffer的区别

    首先,考虑到安全和性能问题,String类是不可变的,所以在字符串拼接的时候如果使用String的话性能会很低。因此就需要使用另一个数据类型StringBuffer。

    StringBuffer:

    • 它提供了append和insert方法可用于字符串的拼接
    • 它使用了synchronized来保证线程安全

    StringBuffer中append()方法:

    			   public synchronized StringBuffer append(Object obj){
                       toStringCache = null;
                       super.append(String.valueOf(obj));
                       return this;
                   }
                   public synchronized StringBuffer append(String str){
                      toStringCache = null;
                       super.append(String.valueOf(str));
                       return this;
                   }
    

    但是由于StringBuffer保证了线程的安全,所以性能上来讲 —— 很低。
    于是在JDK1.5中推出了线程不安全,但是性能相对而言较高的StringBuilder。其功能和StringBuffer一样。

    String两种创建方法的异同

    我们先来看看创建String的两种方式:

    方式一:

    String s1 = "java";  //直接赋值
    

    方式二:

    String s2 = new String("java");  //对象创建
    

    这两种方法都可以创建字符串,但是两个方法在JVM的存储区域截然不同

    方法一:
    jvm会先到字符串常量池中寻找是否有相同的字符串,如果有就返回常量句柄;如果没有该字符串,就先在常量池中创建此字符串,然后再返回常量句柄。

    方法二:
    直接在堆中创建此字符串,只有调用intern()才会放入字符串常量池中。

    举例:

    		   String s1 = new String("java");
               String s2 = s1.intern();
               String s3 = "java";
               System.out.println(s1==s2); //false
               System.out.println(s2==s3); //true
    

    (s2,s3指向堆中常量池的“java”,s1指向堆中的“java”对象)

    == 补充:jdk1.7之后把永生代换成了元空间,把字符串常量池从方法区移到了java堆上 ==

    编译器对String字符串的优化

    我们经常会用“+”来拼接两个字符串。即使是这样拼接的字符串,在进行比较时,也不会出现和结果相同字符串不对等的情况。这是编译器对于String的优化。

    举例:

    			String s1 = "ja" + "va";
                String s2 = "java";
                System.out.println(s1==s2); //true
    
  • 相关阅读:
    征战蓝桥 —— 2017年第八届 —— C/C++A组第7题——正则问题
    征战蓝桥 —— 2017年第八届 —— C/C++A组第7题——正则问题
    征战蓝桥 —— 2017年第八届 —— C/C++A组第7题——正则问题
    征战蓝桥 —— 2017年第八届 —— C/C++A组第8题——包子凑数
    征战蓝桥 —— 2017年第八届 —— C/C++A组第8题——包子凑数
    征战蓝桥 —— 2017年第八届 —— C/C++A组第8题——包子凑数
    征战蓝桥 —— 2017年第八届 —— C/C++A组第9题——分巧克力
    征战蓝桥 —— 2017年第八届 —— C/C++A组第9题——分巧克力
    征战蓝桥 —— 2017年第八届 —— C/C++A组第9题——分巧克力
    征战蓝桥 —— 2017年第八届 —— C/C++A组第10题——油漆面积
  • 原文地址:https://www.cnblogs.com/scywkl/p/12489672.html
Copyright © 2011-2022 走看看