java const string_详解java String

java基础(3)--详解String

其实与八大基本数据类型一样,String也是我们日常中使用非常频繁的对象,但知其然更要知其所以然,现在就去阅读源码深入了解一下String类对象,并解决一些我由来已久的疑问。

为什么String是不可变序列

String类使用final修饰的,所以不可以通过继承方式来修改String。

String类字符串存储是使用final修饰的value数组实现的,所以不可以通过修改value数组来修改String。但是数组其实也是一个引用,那能不能通过修改引用来达到修改String的目的?

下面来看个例子:

public class Test03 {

public static void main(String[] args) {

char[] arr = new char[]{'a', 'b', 'c', 'd'};

String s = new String(arr);

arr[0] = 'b';

System.out.println(s);

}

}

abcd

那为什么不能通过修改引用来修改String呢,看看源码

public String(char value[]) {

this.value = Arrays.copyOf(value, value.length);

}

String通过拷贝数组保证了本身不会被修改

String类的方法返回的字符串只要不是原字符串就会new一个对象。

public String substring(int beginIndex) {

if (beginIndex < 0) {

throw new StringIndexOutOfBoundsException(beginIndex);

}

int subLen = value.length - beginIndex;

if (subLen < 0) {

throw new StringIndexOutOfBoundsException(subLen);

}

return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);

}

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);

}

还有等等......

String类用"=="进行比较的问题

看下面一段代码

public class Test03 {

public static void main(String[] args) {

String s1 = "helloWorld";

String s2 = "hello" + "World";

String s3 = "helloWorld";

String s4 = "hello";

String s5 = "World";

final String s6 = "World";

String s7 = s4 + s5;

String s8 = "hello" + s6;

String str1 = new String("helloWorld");

String str2 = new String("helloWorld");

System.out.println(s1 == s2);

System.out.println(s1 == s3);

System.out.println(s1 == s7);

System.out.println(s1 == s8);

System.out.println(str1 == str2);

System.out.println(str2 == s1);

}

}

true

true

false

true

false

false

一共进行了5次比较,现在一一道来

第一次和第二次之所以都为true,是因为两者的引用都指向了字符串常量池中的"helloWorld",虚拟机会在编译期间进行优化,字面常量相”+“会直接进行拼接而不是调用其他方法。

当字符串拼接存在不是字符常量而是一个变量的时候,虚拟机在编译期间不会将其进行优化,而是用会在堆上生成一个对象,所以第三个比较是false;但如果String对象使用final修饰,那么他就是不可修改的常量,这时等同于是字符常量拼接,虚拟机才会无顾忌的将其优化,所以第四个比较为true。

最后一部分对象的比较就比较容易了,由于是在堆上分配内存的,所以内容是相等的,但是地址引用并不相等,所以都为false。

StringBuilder和StringBuffer

由于String本身不可修改,所以Java提供了StirngBuiler和StringBuffer来弥补这一空缺。现在String之间使用”+“的使用的时候实际上是调用StringBuilder的append方法完成的。

先看一个例子

public class Test03 {

public static void main(String[] args) {

String s = "hello";

for (int i = 0; i < 100; i++){

s += "hello";

}

}

}

再看看反编译

Compiled from "Test03.java"

public class base.Test03 {

public base.Test03();

Code:

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: return

public static void main(java.lang.String[]);

Code:

0: ldc #2 // String hello

2: astore_1

3: iconst_0

4: istore_2

5: iload_2

6: bipush 100

8: if_icmpge 37

11: new #3 // class java/lang/StringBuilder

14: dup

15: invokespecial #4 // Method java/lang/StringBuilder."":()V

18: aload_1

19: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

22: ldc #2 // String hello

24: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

27: invokevirtual #6 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

30: astore_1

31: iinc 2, 1

34: goto 5

37: return

}

可以看出实际上在进行字符串拼接的时候,是调用了append方法进行拼接,再用toString方法返回String对象。

StringBuilder和StringBuffer的不同

StringBuilder是线程不安全的,但是速度快,StringBuffer是线程安全的,他的方法都是用synchronized修饰的,但是速度慢

String,StringBuilder,StringBuffer的效率比较

下面用代码验证一下

String

public class Test03 {

public static void main(String[] args) {

Long start = System.currentTimeMillis();

String s = "hello";

for (int i = 0; i < 10000; i++) {

s += "world";

}

System.out.println(System.currentTimeMillis() - start);

}

}

713

StringBuilder

public class Test03 {

public static void main(String[] args) {

Long start = System.currentTimeMillis();

StringBuilder s = new StringBuilder("hello");

for (int i = 0; i < 10000; i++) {

s = s.append("world");

}

System.out.println(System.currentTimeMillis() - start);

}

}

2

StringBuffer

public class Test03 {

public static void main(String[] args) {

Long start = System.currentTimeMillis();

StringBuffer s = new StringBuffer("hello");

for (int i = 0; i < 10000; i++) {

s = s.append("world");

}

System.out.println(System.currentTimeMillis() - start);

}

}

6

显然StringBuilder > StringBuffer > String;但是在相加字符串较少的时候还是用String效率高点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值