Java之String相关内容详解(字符串和字符串常量池)面试题

Posted 蓝盒子itbluebox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java之String相关内容详解(字符串和字符串常量池)面试题相关的知识,希望对你有一定的参考价值。

1、String可以被继承吗?

String类在声明时使用final关键字修饰,被final关键字修饰的类无法被继承。

Cannot inherit from final "java.lang.String’
无法从最终的“java.lang.String”继承

接下来我们可以看一下String类的源代码片段:

public final class String
    implements java.io.Serializable, Comparable<String>,CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

2、为什么Java语言的开发者,把String类定义为final的呢?

1 主要是为了“效率” 和 “安全性” 的缘故。
若 String允许被继承, 由于它的高度被使用率, 可能会降低程序的性能,所以String被定义成final。

2、 String类中的成员属性也几乎都设计成了private final的,这样String就被设计成一个不变类,这样有助于共享,提高性能。
可以将字符串对象保存在字符串常量池中以供与字面值相同字符串对象共 享。
如果String对象是可变的,那就不能这样共享,因为一旦对某一个String类型变量引用的对象值改变,将同时改变一起共享字符串对象的其他 String类型变量所引用的对象的值。

3、String被设计为不变类,其中的offset,value[]都被设计成private final的,这样在多线程时,对String对象的访问是可以保证安全的。
java程序语言的许多特性依赖于不可变的String对象。

3、字符串和字符串池

(1)字符串

1、字符串的创建

(1)直接创建:String s = “Hello”;
(2)new 创建:String s = new String(“Hello”)

要注意空字符串和null是不同的

public class StringTest{
    public static void main(String[] args) {
        String s1 = "";
        String s2 = new String("");
        String s3 = new String();
        String s4 = null;
        System.out.println("s1.equals(s2)="+s1.equals(s2));
        System.out.println("s2.equals(s3)="+s2.equals(s3));
        System.out.println("s3.equals(s4)="+s3.equals(s4));
        System.out.println("s1.equals(s4)="+s1.equals(s4));
    }
}

(3)除了new (“Hello”)中的类型之外,还能有如下方式:
public class StringTest{
    public static void main(String[] args) {
        String s1 = "Hello1";
        String s2 = new String(s1);
        char []c = {'H','e','l','l','o','2'};
        String s3 = new String(c);  //但是不能String s3 = new String({'H','e','l','l','o','2'})
        byte []b = {'H','e','l','l','o','2'};
        String s4 = new String(b);
        StringBuffer sb = new StringBuffer(new String("Hello4"));
        String s5 = new String(sb);
        StringBuilder sbu = new StringBuilder(new StringBuffer("Hello5"));
        String s6 = new String(sbu);
        System.out.println("s1:"+s1+" s2:"+s2+" s3:"+s3+" s4:"+s4+" s5:"+s5+" s6:"+s6);
    }
}


可以看出还可以以byte[]、char[]、String、StringBuffer、StringBuilder均可作为String构造函数的参数。

(4)vauleOf()创建

普通数据类型 String s1=String.vauleOf(true);
或者是int bl=54;String s1=String.vauleOf(bl);直接将其转换为String.

public class StringTest{
    public static void main(String[] args) {
       String s1 = String.valueOf(true);
       System.out.println("s1:"+s1);
       int bl = 54;
       String s2 = String.valueOf(bl);
       System.out.println("s2:"+s2);
    }
}

(5)toString()

引用数据类型通过调用成员方法toString()来将对象转换为字符串。对与System.out.println(obj);若obj = null返回null

public class StringTest{
    public static void main(String[] args) {
        Object obj = null;
        System.out.println(obj);
    }
}


继续探讨toString()方法,如果调用它的是一个字符串对象包括String,StringBuffer、StringBuilder则返回当前字符串,如果是基础数据的引用、例如Integer,Character,Boolean则会返回对应的int,char,boolean等对应的数据字符串。如果是其他类型对象,重写toString()方法就不说了,但是未重写方法就会输出“包名.类名@哈希码十六进制”(此处包含数组)

package cn.itbluebox;

class A{

}
public class StringTest{

    public static void main(String[] args) {

        A a = new A();
        A a0 = new A();
        System.out.println(a.toString());
        System.out.println(a0);

    }
}

(6)System.out.println()方法

我们常用的System.out.println()方法其实就是将参数转换为字符串,而主要方法,如果是基本类型,就使用valueOf(),若是非null引用就调用toString(),若是null类型数据就是返回null(null不能直接作为参数,只能是某些对象指向null,然后打印此对象的形式)

class A{
}
class B{
    @Override
    public String toString() {
        return "BB";
    }
}
public class StringTest{
    public static void main(String[] args) {
        char []c = {'H','e','l','l','o','2'};//数组
        StringBuffer sb = new StringBuffer(new String("Hello4"));//字符串对象
        Integer i = 9;//基本类型的包装类
        boolean b1 = false;//基本数据类型
        Object o = null;//null
        A a = new A();      //非null无重写
        B b = new B();      //非null有重写
        System.out.println(c);  //打印Hello2
        System.out.println("c.toString():"+c.toString());//打印地址
        System.out.println("i:"+i);
        System.out.println("b1:"+b1);
        System.out.println("o:"+o);
        System.out.println("a:"+a);
        System.out.println("b.toString():"+b.toString());
    }
}

(7)直接+

两个字符串相加
例如:

String s1 = "123"+"456";

字符串和其他相加时会采用和println相同的策略

public class StringTest02 {
    public static void main(String[] args) {
        byte []b = {'H','e','l','l','o','3'};
        Object o = null;
        String s1 = "123"+new Integer(456);
        String s2 = "123"+o;//o对象没有实例化返回null
        String s3 = "123"+false;
        String s4 = "123"+b;
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
        System.out.println(s4);
    }
}


任然来重点看一下字符数组,在+连接符下,会直接调用toString()从而返回其地址,不会访问其内容,编程与其他类型数组一样。

2、字符串的操作

(1)public String concat(String str)进行拼接操作,若str是空字符串,则还返回原理的引用
public class StringTest02 {
    public static void main(String[] args) {
        String s1 = "123";
        String s2 = "456";
        System.out.println("s1:"+s1);
        System.out.println("s1.hashCode():"+s1.hashCode());
        s1 = s1.concat(s2);
        System.out.println("s1:"+s1);
        System.out.println("s1.hashCode():"+s1.hashCode());
    }
}


s1.hashCode():1450575459 可以看出str不为空就会返回一个新的引用

(2)其他相关方法

String replace(char oldChar,char newChar)将所有的oldChar字符替换为newChar,

String toLowerCase()String toUpperCase()转换大小写,

String trim()去空白符,对于这些方法来说若不会改变原有字符串(如果需要改变需要对原有字符串重新赋值),

例如toLowerCase()不含oldChar,转换为小写的不含小写字符串,或不含空白符等就不会修改原引用,

String substring(int beginIndex)String substring(int beginIndex,int endIndex)
是截取第beginIndex+1到结束的字符串和从第beginIndex+1到nedIndex的子字符串

package cn.itbluebox;

import javax.swing.*;

public class StringTest02 {
    public static void main(String[] args) {

        System.out.println("replace↓");
        String s1 = "123123123";
        s1.replace("1","a");
        System.out.println(s1);
        s1 =  s1.replace("1","a");
        System.out.println(s1);

        System.out.println("toUpperCase↓");
        s1.toUpperCase();
        System.out.println(s1);
        s1 = s1.toUpperCase();
        System.out.println(s1);

        System.out.println("toLowerCase↓");
        s1.toLowerCase();
        System.out.println(s1);
        s1 = s1.toLowerCase();
        System.out.println(s1);

        System.out.println("trim↓");
        s1 = "  "+s1+"   "+s1+"    ";
        s1.trim();
        System.out.println(s1);
        s1= s1.trim();
        System.out.println(s1);

        System.out.println("substring↓");
        s1.substring(5);
        System.out.println(s1);
        s1 = s1.substring(5);
        System.out.println(s1);

        s1.substring(2,4);
        System.out.println(s1);
        s1 = s1.substring(2,4);
        System.out.println(s1);

    }
}

(3)其他相关方法

int indexOf(int ch),查询第一次出现的位置,若不含此字符串,

返回-1,不要误以为写错了,确实是参数为int类型,这里指的是Unicode码,

int indexOf(int ch,int fromIndex)功能相同但要从大于等于fromIndex的下标(注意和第几个分区)开始查询,

int indexOf(String str)提前是str是子字符串,

返回第一个字符的下标,int index(String str,int fromIndex)类似。

package cn.itbluebox;

public class StringTest02 {
    public static void main(String[] args) {
        String s = "abcabcdabcde";
        System.out.println("s.indexOf('b'):"+s.indexOf('b'));
        System.out.println("s.indexOf('b',1):"+s.indexOf('b',1));//返回当前字符串当中b从下角标为1的位置(从第0号位开始)
        System.out.println("s.indexOf('b',2):"+s.indexOf('b',2));//返回当前字符串当中b从下角标为2的位置(从第0号位开始)
        System.out.println("s.indexOf(\\"abc\\"):"+s.indexOf("abc"));//返回当前字符串当中abc从下角标为0的位置(从第0号位开始)
        System.out.println("s.indexOf(\\"abc\\",1):"+s.indexOf("abc",1));//返回当前字符串当中abc从下角标为1的位置(从第0号位开始)
        System.out.println("s.indexOf(\\"ab\\",-1):"+s.indexOf("ab",-1));//返回当前字符串当中ab从下角标为-1的位置(从第0号位开始)
        System.out.println("s.lastIndexOf(\\"ab\\"):"+s.lastIndexOf("ab"));//s.length-1号下角标的相当于最后一个元素,往前第一次ab出现对应的下角标的值
        System.out.println("s.lastIndexOf(\\"c\\",8):"+s.lastIndexOf("c",8));//8号下角标的相当于最后一个元素,往前第一次c出现对应的下角标的值
        System.out.println("s.lastIndexOf(\\"abc\\",7):"+s.lastIndexOf("abc",7));//7号下角标的相当于最后一个元素,往前第一次abc出现对应的下角标的值
        System.out.println("s.lastIndexOf(\\"abc\\",29):"+s.lastIndexOf("abc",29));//29号下角标的相当于最后一个元素,往前第一次abc出现对应的下角标的值
    }
}

(4)字符串的比较

int compareTo(String another);(参数不能是null???),
返回值第一个不相同字符unicode码差值,若两一个字符串是另外一个字符串字串,
返回字符串长度差值,若两串相同则返回0,
此外还有int compareToIgnoreCase(String another);比较方法与其类似,但是忽略大小写。

判断两个字符串相等不能用等号==,要用boolean equals(Object anObj)你看到的没错正是Object类型的参数,

但是你用其他对象做参数,参数的值为null的返回值返回false,
即使是StringBuffer对象也一样,null可以作为参数但是永远返回false。

boolean equalsIgnoreCase(String another)忽略大小写。

具体案例

public class StringTest02 {
    public static void main(String[] args) {

        String a = "123"流程图详解 new String(“abc“) 创建了几个字符串对象

流程图详解 new String(“abc“) 创建了几个字符串对象

《java基础知识》Java字符串详解

Java疯狂作图之剖释String类之妈见夸之作

Java高级编程--常用类之字符串相关类StringStringBufferStringBuilder

Java之Io知识详解