Java 教程 在线

1336Java String 类

String 类的常见面试问题

面试题一:

String s1 = "abc";            // 常量池
String s2 = new String("abc");     // 堆内存中
System.out.println(s1==s2);        // false两个对象的地址值不一样。
System.out.println(s1.equals(s2)); // true

面试题二:

String s1="a"+"b"+"c";
String s2="abc";
System.out.println(s1==s2);
System.out.println(s1.equals(s2));

java 中常量优化机制,编译时 s1 已经成为 abc 在常量池中查找创建,s2 不需要再创建。

面试题三:

String s1="ab";
String s2="abc";
String s3=s1+"c";
System.out.println(s3==s2);         // false
System.out.println(s3.equals(s2));  // true

先在常量池中创建 ab ,地址指向 s1, 再创建 abc ,指向 s2。对于 s3,先创建StringBuilder(或 StringBuffer)对象,通过 append 连接得到 abc ,再调用 toString() 转换得到的地址指向 s3。故 (s3==s2)false

1335Java String 类

java 中的字符串的加算法

String a = "a";
String b = "b";
String c = a + b;

相当于:

String c = new StringBuffer().append(a).append(b).toString();

对于字符串的加运算,当编译成 class 文件时,会自动编译为 StringBuffer 来进行字符串的连接操作。

同时对于字符串常量池:

当一个字符串是一个字面量时,它会被放到一个常量池中,等待复用。

String a = "saff";
String b = "saff";
String c = new String("saff");
System.out.println(a.equal(b));  // true
System.out.println(a.equal(c));  // true

这个就是字符串的常量池。

1334Java String 类

关于 String 为啥是不可改变的

这里可以根据 jdk 的源码来分析。

字符串实际上就是一个 char 数组,并且内部就是封装了一个 char 数组。

并且这里 char 数组是被 final 修饰的:

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

并且 String 中的所有的方法,都是对于 char 数组的改变,只要是对它的改变,方法内部都是返回一个新的 String 实例。

1333Java String 类

1.对整数进行格式化:%[index$][标识][最小宽度]转换方式

格式化字符串由4部分组成,特殊的格式常以%index$开头,index从1开始取值,表示将第index个参数拿进来进行格式化,[最小宽度]的含义也很好理解,就是最终该整数转化的字符串最少包含多少位数字。剩下2个部分的含义:

标识:

  • '-' 在最小宽度内左对齐,不可以与"用0填充"同时使用
  • '#' 只适用于8进制和16进制,8进制时在结果前面增加一个0,16进制时在结果前面增加0x
  • '+' 结果总是包括一个符号(一般情况下只适用于10进制,若对象为BigInteger才可以用于8进制和16进制)
  • ' ' 正值前加空格,负值前加负号(一般情况下只适用于10进制,若对象为BigInteger才可以用于8进制和16进制)
  • '0' 结果将用零来填充
  • ',' 只适用于10进制,每3位数字之间用","分隔
  • '(' 若参数是负数,则结果中不添加负号而是用圆括号把数字括起来(同'+'具有同样的限制)

转换方式:

d-十进制 o-八进制 x或X-十六进制

上面的说明过于枯燥,我们来看几个具体的例子。需要特别注意的一点是:大部分标识字符可以同时使用。

System.out.println(String.format("%1$,09d", -3123));
System.out.println(String.format("%1$9d", -31));
System.out.println(String.format("%1$-9d", -31));
System.out.println(String.format("%1$(9d", -31));
System.out.println(String.format("%1$#9x", 5689));
//结果为:
//-0003,123
// -31
//-31
// (31)
// 0x1639 

2.对浮点数进行格式化:%[index$][标识][最少宽度][.精度]转换方式

我们可以看到,浮点数的转换多了一个"精度"选项,可以控制小数点后面的位数。

标识:

  • '-' 在最小宽度内左对齐,不可以与"用0填充"同时使用
  • '+' 结果总是包括一个符号
  • ' ' 正值前加空格,负值前加负号
  • '0' 结果将用零来填充
  • ',' 每3位数字之间用","分隔(只适用于fgG的转换)
  • '(' 若参数是负数,则结果中不添加负号而是用圆括号把数字括起来(只适用于eEfgG的转换)

转换方式:

  • 'e', 'E' -- 结果被格式化为用计算机科学记数法表示的十进制数
  • 'f' -- 结果被格式化为十进制普通表示方式
  • 'g', 'G' -- 根据具体情况,自动选择用普通表示方式还是科学计数法方式
  • 'a', 'A' -- 结果被格式化为带有效位数和指数的十六进制浮点数

3.对字符进行格式化:

对字符进行格式化是非常简单的,c表示字符,标识中'-'表示左对齐,其他就没什么了。

1332Java String 类

length() 方法,length 属性和 size() 方法的区别:

  • 1、length() 方法是针对字符串来说的,要求一个字符串的长度就要用到它的length()方法;
  • 2、length 属性是针对 Java 中的数组来说的,要求数组的长度可以用其 length 属性;
  • 3、Java 中的 size() 方法是针对泛型集合说的, 如果想看这个泛型有多少个元素, 就调用此方法来查看!

这个例子来演示这两个方法和一个属性的用法:

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        String array[] = { "First", "Second", "Third" };
        String a = "HelloWorld";
        List<String> list = new ArrayList<String>();
        list.add(a);
        System.out.println("数组array的长度为" + array.length);
        System.out.println("字符串a的长度为" + a.length());
        System.out.println("list中元素个数为" + list.size());

    }
}

输出的值为:

数组array的长度为3
字符串a的长度为10
list中元素个数为1