课程咨询 :186 8716 1620      qq:2066486918

昆明Java培训 > 达内新闻 > java培训:java中的字符串相关知识整理
  • java培训:java中的字符串相关知识整理

    发布:昆明Java培训      来源:达内新闻      时间:2016-09-22

  • 字符串为什么这么重要

    昆明Java培训机构的老师发现很多人写了多年java的开发应该对String不陌生,但是却越发觉得它陌生。每学一门编程语言就会与字符串这个关键词打不少交道。说明它真的很重要。

    字符串就是一系列的字符组合的串,如果写过C/C++的应该就了解,在字符串的操作上会有许多操作的函数与类,用于简化代码的开发。一方面是因为字符串在代码中会频繁用到,另一方面是因为字符串的操作非常麻烦。

    最初昆明Java培训机构的老师知道String的特殊待遇就是在delphi中,因为String在delphi里是一个关键字存在,与其他的基本类型是不一样的。那时就了解到了许多相关的知识。在java/.net也都对string做了专门的处理,可见重要性。

    正因为字符串在程序中用的多,而且操作也多这就会带来内存占用与性能的问题,所需要特殊的关照一下,想象一下一个日志记录系统一天时间得用上多少字符串变量。

    了解一下java中的String

    java中提供了String类支持字符串的功能,毕竟字符串本质就是一堆字符的组合,那么就来看看它有什么特点吧。

    String的特点

    String把字符串还是存放在一个char数组中的,数据的操作围绕它展开,但有点特别的地方,代码如下

    private final char value[];

    可以发现这个char value[]是加了final的,也就是说一旦创建了值就不可变。这样就会导致每一次创建String只会有一个值,再对其进行字符串操作也必须生成新的值。java对这个处理使用了字符串常量池的概念。就是把字符串丢到一个池里,如果相同就用相同的。当然这也有个前提,就是要用下面的方式

    String s = "abc";

    这样做的时候jvm会在编译期就确定了,在运行时会先在常量池里查找是否有"abc",没有就添加并返回,有的话返回常量池的对象。这样做的好处是对于相同的字符串就不需要重复创建啦。但是如果使用下面的代码

    String s1 = new String("abc");

    这个时候情景就变了,这里jvm会在堆栈里创建一个对象s1,只不过s1里的value也是指向"abc"的。后面在看字符串比较的时候会发现区别。

    字符串比较看一段代码:

    String s = "abc";

    String s1 = "abc";

    if (s == s1) {

    System.out.println("s == s1");

    }

    问:这时s==s1吗?

    答案是相等的,为什么呢?其实jvm会在s1创建时去常量区查找是否有相同值的字符串,如果有就返回给s1,这样s1就和s指向了同一个字符串,所以是相等的。

    但是还有一种情况就不一样,

    String s = "abc";

    String s3 = new String("abc");

    if (s == s3) {

    System.out.println("s == s3");

    }

    else {

    System.out.println("s != s3");

    }

    这个时候应该print出s != s3,这是因为new一个String对象后确实会创建一个新的变量。所以使用==比较的话自然就返回false了。

    用到equals比较呢?

    String s = "abc";

    String s2 = new String("abc");

    if (s.equals(s2)) {

    System.out.println("s = s2");

    }

    else {

    System.out.println("s != s2");

    }

    打印是s = s2,因为==是用于比较两个地址,而equals是用于比较两个变量的值。可以看一下equals的代码

    public boolean equals(Object anObject) {

    if (this == anObject) {

    return true;

    }

    if (anObject instanceof String) {

    String anotherString = (String)anObject;

    int n = value.length;

    if (n == anotherString.value.length) {

    char v1[] = value;

    char v2[] = anotherString.value;

    int i = 0;

    while (n-- != 0) {

    if (v1[i] != v2[i])

    return false;

    i++;

    }

    return true;

    }

    }

    return false;

    }

    在equals中,先是比较是否地址相同,如果不相同比较value,因为value都是"abc"自然就返回true。

    intern方法

    String里有一个intern方法,我们可以先试一下面的代码。

    String s = "abc";

    String s3 = new String("abc");

    if (s.intern() == s3.intern()) {

    System.out.println("s.intern = s3.intern");

    }

    else {

    System.out.println("s.intern != s3.intern");

    }

    还是上面的s和s3,如果使用各自的intern方法返回的值比较则会输出s.intern = s3.intern。找了找资料结合注释了解到,这个intern方法其实是从字符串常量池里返回当前字符串,如果当前字符串已经存在了则返回当前字符串,如果当前字符串不存在,则将当前字符串放入常量池再返回。

    有了这个解释就明白了,s和s3都通过intern返回的那么都是常量池里的"abc"咯,所以intern比较时是相等的。

    认识一下StringBuffer和StringBuilder

    StringBuffer和StringBuilder哪一个是线程安全的?

    面试时遇到的这个问题,你是不是会突然有点懵,没太注意过这两个类,而且印象中java里只有一个StringBuffer呀?回来看了一下代码原来StringBuffer是线程安全的,也就是在字符串操作的方法上都有synchronized。

    于是打开代码注释发现是Jdk1.5才开始有的StringBuilder,而且在后面版本加了个不加锁的类,看样子是解决非并发场景下的效率问题,不加锁对于操作大字符串还是有性能提升的。

    嗯,不错,get了一个小知识。

    出于好奇看了一下这两个类的代码,与String真有些类似,只不过这时的chat[]已经是不带final的咯,这样就避免了String类操作时产生一堆字符串对象的问题。

    char[] value;

    StringBuffer和StringBuilder的作用

    既然已经有了String,那这两个家伙有什么用呢?其实问题还是要和String的原理有关系。因为String是通过常量池管理的,这样解决的是相同字符串重复创建的问题,但大部分字符串都是不一样的,特别是在做字符串拼接操作时,如果用String的+进行拼接就会产生大量的字符串常量,非常的消耗性能与空间。

    为解决这个问题就用到StringBuffer,本质上也就是通过一个可变的字符序列,在字符串操作时不需要生成新的对象,从而提升内存使用。

    看看StringBuffer是怎么提升这个拼接性能的吧。查看StringBuffer/StringBuilder的代码(JDK1.5+)发现它们都继承于AbstractStringBuilder。很多的代码其实都是在AbstractStringBuilder里完成的。因为这个问题由拼接引出的,在此我们就主要关注一下append方法吧。

    public AbstractStringBuilder append(String str) {

    if (str == null)

    return appendNull();

    int len = str.length();

    ensureCapacityInternal(count + len);//确定容量

    str.getChars(0, len, value, count);//取出str的字符放入到value数组中

    count += len;//count累加

    return this;

    }

    代码还是比较清楚的,整个过程最重要的就是使用String的getChars方法将str的值写入到当前对象的value中。而String的getChars方法如下:

    public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {

    if (srcBegin < 0) {

    throw new StringIndexOutOfBoundsException(srcBegin);

    }

    if (srcEnd > value.length) {

    throw new StringIndexOutOfBoundsException(srcEnd);

    }

    if (srcBegin > srcEnd) {

    throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);

    }

    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);

    }

    昆明Java培训机构的老师可以看出最终是做了一个数组的复制,因为在AbstractStringBuilder中的value是个可变的char数组,这样的话对于字符串操作只需要在char数组上进行即可。不会像String那样生成新对象,所以说自然就变的高效了。

    推荐文章

上一篇:【昆明Java培训】java设计模式--工厂模式

下一篇:昆明java培训班:java泛型接口

最新开班日期  |  更多

Java--零基础全日制班

Java--零基础全日制班

开班日期:12/29

Java--零基础业余班

Java--零基础业余班

开班日期:12/29

Java--周末提升班

Java--周末提升班

开班日期:12/29

Java--零基础周末班

Java--零基础周末班

开班日期:12/29

  • 网址:http://km .java.tedu.cn      地址:昆明市官渡区春城路62号证券大厦附楼6楼
  • 课程培训电话:186 8716 1620      qq:2066486918    全国服务监督电话:400-827-0010
  • 服务邮箱 ts@tedu.cn
  • 2001-2016 达内国际公司(TARENA INTERNATIONAL,INC.) 版权所有 京ICP证08000853号-56