在java中最常见的使用就是对字符串的操作:首先先说一下对字符串的理解:字符串就是一连串字符序列,Java提供了String和StringBuffer两个类来封装字符串,并提供一系列方法来操作字符串对象。接下来对它们一一描述:

String类是不可变类:

即一旦一个String对象被创建以后,包含在这个对象中的字符串是不可改变的,直到这个对象被销毁。

StringBuffer类:

在java中则代表一个字符序列可变的字符串,即一个StringBuffer被创建以后,StringBuffer提供的append()、insert()、reverse()、setChatAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。

StringBuilder类:

它是在jdk1.5新增的一个StringBuilder类,它也代表字符串对象,在这里重点说一下StringBuilder和StringBuffer基本相似,它们底层的构造器基本相同,不同的是StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能的,正因为这个原因,它的性能较好一些。。。

来点刺激的String的源码:

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[]; /** Cache the hash code for the string */
private int hash; // Default to 0 private static final long serialVersionUID = -6849794470754667710L; private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
...

可以看出String是由char[]来实现的,String是final类,也就意味着String类是不可以继承的

注意:刚开始说String是不可以变的就是因为char[]在是private的,并且String类没有提供setter方法,导致无法改变这个String对象 String s = “123456”中的s是对象的引用,对象的引用指向对象。对象是不可变的,但是对象的引用是可变的。

下面分析看一下它们中的方法的源码:

substring

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

concat

 public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}

replace

public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */ while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}

可以发现subString、concat、replace操作都是不是在原字符串进行的,而是创建了一个新的字符串。也就是说,进行了上述操作后,本身的字符串并没有改变。只是返回了一个新的对象的引用。。。

对String操作的任何改变都不会改变原对象,而任何改变String对象的操作都会产生新对象。

如:

String str1 = "java";
str1 = str1 + "struts";
str1 = str1 + "spring";

在这里会产生五个字符串直接量不但有原先的3个还会产生额外两个字符串直接量“javastruts”和“javastrutsspring”。程序中的str1依次指向3个不同的字符串对象。

因为String是不可变的,所以会产生很多的临时变量,在这里就会选择StringBuffer或者StringBuilder,因为它们就会解决这个问题

StringBuffer、StringBuilder有两个属性:length和capacity。

其中length属性表示其包含的字符序列的长度。与String对象length不同的是,StringBuffer、StringBuilder的length是可以改变的,可以通过length()、setLength(int len)方法来访问和修改其字符串序列的长度,capacity属性表示StringBuilder容量,capacity通常比length大,程序通常无须任何关心capacity属性。

 public static void main(String[] args)
{
String str = "";
for(int i = 0;i < 10000;i++)
str += "Hello";
}

通过反编译可以看出每次循环一次都会new 一个StringBuilder对象,然后进行append操作,最后用toString方法返回String对象。试想一下如果这些对象没有被JVM回收,则会造成多大的资源浪费。实际上jvm不傻,他会自动优化为:

StringBuilder sb = new  StringBuilder(string);
sb.append("Hello");
str.toString();

再看一段代码:

public static void main(String[] args)
{
StringBuilder sb = new StringBuilder();
for(int i = 0;i < 10000;i++)
sb.append("Hello");
}

反编译其字节码文件,可以看出new操作只进行了一次,也就是说只生成一个对象,append操作是在原有对象上进行的,因此在循环10000次之后,资源消耗要小得多。

再讲述一下StringBuffer,比StringBuilder多了一个关键字: synchronize。这个关键字在多线程操作的时起到安全保护的作用。

总结:如果在对字符串修改较少的情况下,建议使用String str = “Hello”;这种形式;如果在对字符串修改较多,则用StringBuilder;涉及到多线程,则用StringBuffer

浅谈java中的String、StringBuffer、StringBuilder类的区别以及关系的更多相关文章

  1. 浅谈 Java 字符串(String, StringBuffer, StringBuilder)

    我们先要记住三者的特征: String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 一.定义 查看 API 会发现,String ...

  2. 重温java中的String,StringBuffer,StringBuilder类

    不论什么一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类经常使用的有 3 个: String.StringBuffer.StringBuilder ...

  3. Android/Java 中的 String, StringBuffer, StringBuilder的区别和使用

    Android 中的 String, StringBuffer 和 StringBuilder 是移动手机开发中经常使用到的字符串类.做为基础知识是必须要理解的,这里做一些总结. A.区别 可以从以下 ...

  4. 在JAVA中,String,Stringbuffer,StringBuilder 的区别

    首先是,String,StringBuffer的区别 两者的主要却别有两方面,第一是线程安全方面,第二是效率方面 线程安全方面: String  不是线程安全的,这意味着在不同线程共享一个String ...

  5. Java基础知识 String StringBuffer StringBuilder三者的区别(面试题)

    相同点:String.StringBuffer.StringBuilder最终底层存储与操作的都是char数组,StringBuffer和StringBuilder都继承了AbstractString ...

  6. 浅谈Java中的final关键字

    浅谈Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  7. 浅谈Java中的equals和==(转)

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...

  8. 浅谈Java中的equals和==

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...

  9. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

随机推荐

  1. h5软键盘弹起 底部按钮被顶起问题解决

    解决思路: 当键盘弹起时隐藏掉按钮,键盘隐藏时按钮显示 监测键盘是否弹起(浏览器页面是否发生变化) 代码: 1.定义一个底部按钮 <div class="returnbtn" ...

  2. php 类名和方法名相同(构造函数)

    //php 5.6class father{ public function __construct() { echo __METHOD__; }} class son extends father{ ...

  3. requests库/爬取zhihu表情包

    先学了requests库的一些基本操作,简单的爬了一下. 用到了requests.get()方法,就是以GET方式请求网页,得到一个Response对象.不加headers的话可能会400error所 ...

  4. C++标准模板库(STL)之Stack

    1.Stack的常用用法 stack:栈,一个后进先出的容器. 1.1.stack的定义 加上头文件#include<stack>和using namespace std; stack&l ...

  5. Angular2+ 编译后部署到服务器上页面刷新404问题

    原因:NG2+ 会默认不显示URL后面的文件名 解决方案:使用LocationStrategy方式,然后把URL后的# 替换成index.html# app.module.ts import {Has ...

  6. vue-router路由讲解

    此文章用来系统讲解vue-router路由 安装 只介绍npm安装 npm install vue-router --save 项目所需依赖 在main.js或者app.vue中导入 import V ...

  7. javascript中的自定义属性

    标签的自定义属性: 在开发中,有时需要在标签上添加一些自定义属性用来存储数据或状态. 设置了自定义属性的标签,就是在这个标签上添加了这个属性,浏览器中的html结构中可以看到. 使用点语法(如oWra ...

  8. flask 第五章 WebSocket GeventWebsocket 单聊群聊 握手 解密 加密

    1.WebSocket 首先我们来回顾一下,我们之前用socket学习过的项目有: 1.django 2.flask 3.FTP - 文件服务 HTTP - TCP (特点): 1.一次请求,一次响应 ...

  9. Vue.directive添加全局指令详解

    自定义指令创建: Vue.directive( 'mycolor(指令名称:推荐全部小写,驼峰命名会出现问题,看最后面)' , { bind:function(){}, //本例只介绍inserted ...

  10. linux下socket connect 阻塞方式 阻塞时间控制

    同事今天问我,如何在linux下的c代码里面控制connect的阻塞时间.应用的背景是:linux下的c程序有两个目标IP需要connect,如果用阻塞方式,当其中一个IP不能连接的情况下,程序将阻塞 ...