String基础知识

1. 类说明

1.1. 首先是final修饰

类不能被继承,所以String无子类

1.2. 类实现了Serializable,Comparable,CharSequence接口

  • Serializable:用于序列化
  • Comparable:用于比较
  • CharSequence:用于操作String的value对象,获取长度,指定字符等

1.3. 内部主要成员

  • value:用于存储字符串内容
  • hash:用于存储hash值,默认是0,在0的情况下且value长度大于0,执行hashCode()方法时,会计算hash值

1.4. 构造函数

  • String():空实例化,使用的是空字符串进行实例化
  • String(String original):待参实例化,此时,字符串对象不一致,但是值是一致的

1.5. 主要方法

  • intern():如果当前字符串不在常量池中,则将当前的字符串移动至常量池并返回;如果常量池中存在则直接返回常量池中的字符串(所以,intern的返回值和原始值,有可能是同一个对象,有可能不是同一个对象)
  • charAt(int index):获取String内部value下标为index的char
  • toUpperCase toLowerCase: 转大小写
  • equalsIgnoreCase compareTo: 字符串比较
  • getBytes:转字节数组
  • split substring:字符串分割截取

2. 案例介绍

2.1. 字符串实例化

public class TestString {
    public static void main(String[] args) throws Exception {
        String a = "11";
        String a1 = new String("11");

        Field valueField = String.class.getDeclaredField("value");
        valueField.setAccessible(true);
        char[] value = (char[])valueField.get(a);
        value[0] = '2';

        System.out.println("待参构造,String对象不一致,但是值一致");
        System.out.println("a == a1:" + (a == a1));
        System.out.println("由于通过反射将a变量第一个字符改成了2,所以a的值从11变成了21");
        System.out.println("a = " + a);
        System.out.println("a1 = " + a1);
    }
}

运行结果:

待参构造,String对象不一致,但是值一致
a == a1:false
由于通过反射将a变量第一个字符改成了2,所以a的值从11变成了21
a = 21
a1 = 21

 所以,String的对象不一样,但是值是同一个对象

2.2. intern方法

public class TestString {
    public static void main(String[] args) throws Exception {
        // 初始化常量会直接进入常量池
        String a = "11";
        String a1 = new String("11");
        // intern会返回常量池中的字符串
        String intern = a1.intern();

        System.out.println("a == a1: " + (a == a1));
        System.out.println("a == intern: " + (a == intern));
        System.out.println("a1和intern不是同一个对象: " + (a1 == intern));
    }
}

运行结果:

a == a1: false
a == intern: true
a1和intern不是同一个对象: false

public class TestString {
    public static void main(String[] args) throws Exception {
        String a = "1";
        String b = "2";
        String a1 = a + b;
        String intern = a1.intern();
        System.out.println("a1和intern是同一个对象: " + (a1 == intern));
    }
}

a1和intern是同一个对象: true

由于常量池中没有"12"所以将a1移动到常量池

2.3. 加法操作

public class TestString {
    public static void main(String[] args) throws Exception {
        String a = "1";
        String b = "2";
        String a1 = a + b;
        String a2 = "1" + "2";
        String a3 = "12";
        System.out.println("变量相加生成新对象: " + (a1 == a2));
        System.out.println("常量相加不生成新对象: " + (a2 == a3));
    }
}

变量相加生成新对象: false
常量相加不生成新对象: true

3. 常见问答

结合上面的描述,再来看看面试的时候会问什么问题呢

3.1. 解释String为什么不可变?String a = "1"; a = "2";

答:因为用final修饰,所以String对象创建后不能再进行修改了;因此当前场景下其实生成了两个字符串对象,而不是把原本的字符串对象改成了"2",而是a指向了新的实例

注:非要抬杠的话,可以说用反射可以做到去修改字符串,然后没有生成新的String但是值变了(大家高兴就好)

3.2. 下面代码会生成几个字符串对象?

String a = "1";String b = "1";

答:1个

String a = "1";String b = a + "";

答:2个

String a = "1";String b = a + "";String c = b.intern();

答:2个

注:这个题目随便都能出,关键要理解

如果自己不确定,可以用idea等工具去看

3.3. 问两个String对象通过方法交换值(不使用反射)

答:做不到,用反射可以

大家需要注意这个地方,可能下意识会说用中间变量中转,那就尴尬了

看一下反例

public class StringSwapFail {
    public static void main(String[] args) {
        String a = "1";
        String b = "2";
        swap(a, b);
        System.out.println("外部:a=" + a + ";b=" + b);
    }
    private static void swap(String a, String b) {
        String swapVal = a;
        a = b;
        b = swapVal;
        System.out.println("内部:a=" + a + ";b=" + b);
    }
}

执行结果:

内部:a=2;b=1
外部:a=1;b=2 

原因呢,如图


可以的反射例子

public class StringSwap {
    public static void main(String[] args) {
        String a = "a";
        String b = "b";
        swap(a, b);
        System.out.println("a=" + a + ";b=" + b);
    }
    private static void swap(String a, String b) {
        try {
            // 获取字段
            Field fieldValue = String.class.getDeclaredField("value");
            Field fieldHash = String.class.getDeclaredField("hash");
            // 设置字段可访问
            fieldValue.setAccessible(true);
            fieldHash.setAccessible(true);
            // 交换值
            Object swapVal = fieldValue.get(a);
            fieldValue.set(a, fieldValue.get(b));
            fieldValue.set(b, swapVal);
            // 交换hash值
            swapVal = fieldHash.get(a);
            fieldHash.set(a, fieldHash.get(b));
            fieldHash.set(b, swapVal);
            // 也可以设置0,String内部对于0会去生成hash值
            // fieldHash.setInt(a, 0);
            // fieldHash.setInt(b, 0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

-- 有缘登山,寒山不寒

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值