第十八天

相信String这个类是Java中使用得最频繁的类之一,今天就来和大家一起学习一下StringStringBuilderStringBuffer

 

一、从源码的角度初步了解String

想要了解一个类,最好的办法就是看这个类的实现源代码,打开这个类的源码文件就会发现String类是被final修饰的:

进一步分析可以看出几点:

1String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。在早期的JVM实现版本中,被final修饰的方法会被转为内嵌调用以提升执行效率。而从Java SE5/6开始,就渐渐摈弃这种方式了。因此在现在的Java SE版本中,不需要考虑用final去提升方法调用效率。只有在确定不想让该方法被覆盖时,才将方法设置为final

 

2源码中String类中的成员属性可以看出,String类其实是通过char数组来保存字符串的。

 

 

3从上面的两个方法可以看出,无论是sub还是concat操作都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。

  在这里要永远记住一点:

  String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象

  在了解了于String类基础的知识后,下面来看一些在平常使用中容易忽略和混淆的地方。

 

 

.深入理解StringStringBufferStringBuilder

1.String str="hello world"String str=new String("hello world")的区别

import java.util.Objects;

public class Demo {
    public static void main(String[] args) {
    String s1 = "hello";
    String s2 = new String("hello");
    String s3 = "hello";
    String s4 = new String("hello");
    System.out.println(s1 == s2);//false
    System.out.println(s1 == s3);//true
    System.out.println(s2 == s4);//false
    }
}

2.StringStringBuffer以及StringBuilder的区别

StringBuffer以及StringBuilder的功能和String一样都是可以进行字符串的操作。

既然在Java中已经存在了String类,那为什么还需要StringBuilderStringBuffer类呢?

那么看下面这段代码:

import java.util.Objects;

public class Demo {
    public static void main(String[] args) {
        String string = "";
        for (int i = 0; i < 100; i++) {
            string += "hello";// string = string + hello
            //传统的String做字符串拼接,循环100次,new100字符串对象
        }
        System.out.println(string);
    }
}

从上面String的源码中我们可以分析出:这句 string += "hello";的过程相当于将原有的string变量指向的对象内容取出与"hello"作字符串相加操作再存进另一个新的String对象当中,再让string变量指向新生成的对象。也就是说这个循环执行完毕new出了10000个对象,试想一下,如果这些对象没有被回收,会造成多大的内存资源浪费。

再看下面这段代码:

import java.util.Objects;

public class Demo {
    public static void main(String[] args) {
        StringBuilder sbBuilder = new StringBuilder();
        for (int i = 0; i < 100; i++) {
            sbBuilder.append("hello");
        }
    System.out.println(sbBuilder.toString());
    }
}

这断代码和前面的功能一样,但是这里的10000次循环new操作只进行了一次,也就是说只生成了一个对象,append操作是在原有对象的基础上进行的。因此在循环了10000次之后,这段代码所占的资源要比上面小得多。这就是StringstringBuilder的最最主要的区别。

其实:字符串拼接从jdk5开始编译器就已经完成了自动优化,当String+常量的代码在编译的时候就会自动被优化为new一个StringBuilder,再调用append方法。

那么有人会问既然有了StringBuilder类,为什么还需要StringBuffer类?查看源代码便一目了然,事实上,StringBuilderStringBuffer类拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized,不用多说,这个关键字是在多线程访问时起到安全保护作用的,也就是说StringBuffer是线程安全的。有关线程的问题,我们讲多线程的时候在详细讲解!

总结:这三个类是各有利弊,应当根据不同的情况来进行选择使用

1、循环外字符串拼接可以直接使用String+操作,没有必要通过StringBuilder进行append.

2、有循环体的话,好的做法是在循环外声明StringBuilder对象,在循环内进行手动append

不论循环多少层都只有一个StringBuilder对象。

3、当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer

 

 

 

 

 

 

相信String这个类是Java中使用得最频繁的类之一,今天就来和大家一起学习一下StringStringBuilderStringBuffer

 

一、从源码的角度初步了解String

想要了解一个类,最好的办法就是看这个类的实现源代码,打开这个类的源码文件就会发现String类是被final修饰的:

 

进一步分析可以看出几点:

1String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。在早期的JVM实现版本中,被final修饰的方法会被转为内嵌调用以提升执行效率。而从Java SE5/6开始,就渐渐摈弃这种方式了。因此在现在的Java SE版本中,不需要考虑用final去提升方法调用效率。只有在确定不想让该方法被覆盖时,才将方法设置为final

 

2源码中String类中的成员属性可以看出,String类其实是通过char数组来保存字符串的。

 

 

3从上面的两个方法可以看出,无论是sub还是concat操作都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。

  在这里要永远记住一点:

  String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象

  在了解了于String类基础的知识后,下面来看一些在平常使用中容易忽略和混淆的地方。

 

 

.深入理解StringStringBufferStringBuilder

1.String str="hello world"String str=new String("hello world")的区别

public class Main {         

    public static void main(String[] args) {

        String str1 = "hello world";

        String str2 = new String("hello world");

        String str3 = "hello world";

        String str4 = new String("hello world");

         

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

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

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

    }

}

这段代码的输出结果为

 

2.StringStringBuffer以及StringBuilder的区别

StringBuffer以及StringBuilder的功能和String一样都是可以进行字符串的操作。

既然在Java中已经存在了String类,那为什么还需要StringBuilderStringBuffer类呢?

那么看下面这段代码:

public class Main {

    public static void main(String[] args) {

        String string = "";

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

            string += "hello";

        }

    }

}

从上面String的源码中我们可以分析出:这句 string += "hello";的过程相当于将原有的string变量指向的对象内容取出与"hello"作字符串相加操作再存进另一个新的String对象当中,再让string变量指向新生成的对象。也就是说这个循环执行完毕new出了10000个对象,试想一下,如果这些对象没有被回收,会造成多大的内存资源浪费。

 

再看下面这段代码:

public class Main {      

    public static void main(String[] args) {

        StringBuilder stringBuilder = new StringBuilder();

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

            stringBuilder.append("hello");

        }

    }

}

这断代码和前面的功能一样,但是这里的10000次循环new操作只进行了一次,也就是说只生成了一个对象,append操作是在原有对象的基础上进行的。因此在循环了10000次之后,这段代码所占的资源要比上面小得多。这就是StringstringBuilder的最最主要的区别。

其实:字符串拼接从jdk5开始编译器就已经完成了自动优化,当String+常量的代码在编译的时候就会自动被优化为new一个StringBuilder,再调用append方法。

 

那么有人会问既然有了StringBuilder类,为什么还需要StringBuffer类?查看源代码便一目了然,事实上,StringBuilderStringBuffer类拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized,不用多说,这个关键字是在多线程访问时起到安全保护作用的,也就是说StringBuffer是线程安全的。有关线程的问题,我们讲多线程的时候在详细讲解!

 

 

 

总结:这三个类是各有利弊,应当根据不同的情况来进行选择使用

1、循环外字符串拼接可以直接使用String+操作,没有必要通过StringBuilder进行append.

2、有循环体的话,好的做法是在循环外声明StringBuilder对象,在循环内进行手动append

不论循环多少层都只有一个StringBuilder对象。

3、当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/jikebin/p/12623862.html