当前位置: 首页 > news >正文

深圳网站如何制作/百度搜索推广的定义

深圳网站如何制作,百度搜索推广的定义,网站开发项目实战,手机可以制作网站吗目录 一、String 二、StringBuilder&StringBuild 三、三类对比 String无疑是Java中使用最频繁的类之一,而String类也有一定的缺陷,随后衍生出了StringBuilder和StringBuffer,当然它们俩也有一定的缺陷。所以我们在选择字符串类型时需要…

目录

一、String

二、StringBuilder&StringBuild

三、三类对比


String无疑是Java中使用最频繁的类之一,而String类也有一定的缺陷,随后衍生出了StringBuilder和StringBuffer,当然它们俩也有一定的缺陷。所以我们在选择字符串类型时需要考虑下使用哪个会比较合适。

一、String

1、成员属性

我们先来看一下String类的成员属性(jdk1.7)

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence
{/** The value is used for character storage. */private final char value[];/** The offset is the first index of the storage that is used. */private final int offset;/** The count is the number of characters in the String. */private final int count;/** Cache the hash code for the string */private int hash; // Default to 0/** use serialVersionUID from JDK 1.0.2 for interoperability */private static final long serialVersionUID = -6849794470754667710L;//......}

可见:

String类其实是通过char数组来保存字符串的

String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。

源码的注释中有这一句话:

Strings are constant; their values cannot be changed after theyare created. String buffers support mutable strings.

字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变字符串。

我们可以测试一下:

public class test {public static void main(String[] args) {String s = "abc";System.out.println("s之前的hashCode:"+s.hashCode());s = "abc" + "1";System.out.println("s之后的hashCode:"+s.hashCode());}
}

我们都知道hashcode关联到对象在内存中的存储位置,字符串经过拼接操作后hashcode值改变了,也就是说s这个引用指向了另一个对象"abc1"。可以看一下String操作时内存变化的图:

这就会导致每次对String的操作都会生成新的String对象,短短的两个字符串,却需要开辟三次内存空间,这样不仅效率低下,而且大量浪费有限的内存空间。

2、方法

下面是取子串、拼接以及替换方法的源码:

public String substring(int beginIndex, int endIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}if (endIndex > count) {throw new StringIndexOutOfBoundsException(endIndex);}if (beginIndex > endIndex) {throw new StringIndexOutOfBoundsException(endIndex - beginIndex);}return ((beginIndex == 0) && (endIndex == count)) ? this :new String(offset + beginIndex, endIndex - beginIndex, value);
}public String concat(String str) {int otherLen = str.length();if (otherLen == 0) {return this;}char buf[] = new char[count + otherLen];getChars(0, count, buf, 0);str.getChars(0, otherLen, buf, count);return new String(0, count + otherLen, buf);
}public String replace(char oldChar, char newChar) {if (oldChar != newChar) {int len = count;int i = -1;char[] val = value; /* avoid getfield opcode */int off = offset;   /* avoid getfield opcode */while (++i < len) {if (val[off + i] == oldChar) {break;}}if (i < len) {char buf[] = new char[len];for (int j = 0 ; j < i ; j++) {buf[j] = val[off+j];}while (i < len) {char c = val[off + i];buf[i] = (c == oldChar) ? newChar : c;i++;}return new String(0, len, buf);}
}

源码的逻辑清晰易读,可见无论是substring、concat还是replace操作都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说进行这些操作后,最原始的字符串并没有被改变。

三、String字符串常量池

为了解决大量频繁的创建字符串而带来的高昂的时间与空间代价,JVM在堆内存(jdk1.7之后)中为字符串开辟一个字符串常量池,类似于缓存区。创建字符串常量时,首先坚持字符串常量池是否存在该字符串;存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中。

String其中两个实例化方法可以完美理解字符串常量池:

public class test {   public static void main(String[] args) {String str1 = "hahaha";String str2 = new String("hahaha");String str3 = "hahaha";String str4 = new String("hahaha");System.out.println(str1==str2);System.out.println(str1==str3);System.out.println(str2==str4);}
}

运行结果:

在上述代码中,String str1 = "hahaha";和String str3 = "hahaha"; 都在编译期间生成了 字面常量和符号引用,运行期间字面常量"hahaha"被存储在运行时常量池,只保存了一份)。通过这种方式来将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。

而通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的。

 

字符串常量池只能解决频繁地重复创建字面量相同字符串。还需要使用Java提供的其他两个操作字符串的类——StringBuffer类和StringBuild类来对此种变化字符串进行处理。

二、StringBuilder&StringBuild

先来看三者的继承结构

和 String 类不同的是,因为实现了Appendable接口,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

而StringBuilder和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。原因很简单,我们可以看一下StringBuilder和 StringBuffer中的insert方法的源码:

StringBuilder的insert方法:

public StringBuilder insert(int index, char str[], int offset,int len){super.insert(index, str, offset, len);return this;
}

StringBuffer的insert方法:

public synchronized StringBuffer insert(int index, char str[], int offset,int len){super.insert(index, str, offset, len);return this;
}

事实上,StringBuilder和StringBuffer类拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized,不用多说,这个关键字是在多线程访问时起到安全保护作用的,也就是说StringBuffer是线程安全的。

StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

 

具体的方法使用可以参考api手册,就不在此测试了~

不过三者之间的转换可以注意一下:

  • String转换成StringBuffer:构造方法和append方法;
  • StringBuffer转换成String:构造方法和toString方法。

 

三、三类对比

 StringStringBufferStringBuilder
对象类型字符串常量。属于不可变类(每次对String的操作都会生成新的String对象),效率低,浪费大量优先的内存空间字符串变量。属于可变类(任何对它指向的字符串的操作都不会产生新的对象)。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量字符串变量。属于可变类,速度更快
大致执行效率
线程有关线程不安全多线程操作字符串,线程安全单线程操作字符串,线程不安全
适用场景操作少,数据少多线程,操作多,数据多单线程,操作多,数据多

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

接下来我们可以测试一下三类的性能

public class test {private static int time = 50000;public static void main(String[] args) {testString();testStringBuffer();testStringBuilder();}public static void testString () {String s="";long begin = System.currentTimeMillis();for(int i=0; i<time; i++){s += "HappyNewYear";}long over = System.currentTimeMillis();System.out.println("操作"+s.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");}public static void testStringBuffer () {StringBuffer sb = new StringBuffer();long begin = System.currentTimeMillis();for(int i=0; i<time; i++){sb.append("HappyNewYear");}long over = System.currentTimeMillis();System.out.println("操作"+sb.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");}public static void testStringBuilder () {StringBuilder sb = new StringBuilder();long begin = System.currentTimeMillis();for(int i=0; i<time; i++){sb.append("HappyNewYear");}long over = System.currentTimeMillis();System.out.println("操作"+sb.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");}}

运行结果:

对三种类型的的对象进行50000次拼接操作,其效率对比可见一斑!

大致效率:StringBuilder > StringBuffer > String;当然这也不是绝对的,当涉及到很少数目的字符串操作时孰快孰慢就不一定了。

 

另外,String类型拼接时"直接"拼接和"间接"拼接的效率是不同的(jvm在编译器对String类型的优化):

public class test {private static int time = 50000;public static void main(String[] args) {test1String();test2String();}public static void test1String () {long begin = System.currentTimeMillis();for(int i=0; i<time; i++){String s = "I"+"love"+"java";}long over = System.currentTimeMillis();System.out.println("字符串直接相加操作:"+(over-begin)+"毫秒");}public static void test2String () {String s1 ="I";String s2 = "love";String s3 = "java";long begin = System.currentTimeMillis();for(int i=0; i<time; i++){String s = s1+s2+s3;}long over = System.currentTimeMillis();System.out.println("字符串间接相加操作:"+(over-begin)+"毫秒");}}

也就是说对于直接相加字符串,效率很高,因为在编译器便确定了它的值,也就是说形如"Happy"+"New"+"Year"; 的字符串相加,在编译期间便被优化成了"happyNewYear"。。对于间接相加(即包含字符串引用),形如s1+s2+s3; 效率要比直接相加低,因为在编译器不会对引用变量进行优化。

关于+= 与 + 可以看另外一个例子:

public class test {private static int time = 50000;public static void main(String[] args) {testString();testString1();}public static void testString () {String s="";long begin = System.currentTimeMillis();for(int i=0; i<time; i++){s += "Happy";}long over = System.currentTimeMillis();System.out.println("操作 s += 'Happy';型使用的时间为:"+(over-begin)+"毫秒");}public static void testString1 () {String s="";long begin = System.currentTimeMillis();for(int i=0; i<time; i++){s = s + "Happy";}long over = System.currentTimeMillis();System.out.println("操作 s = s + 'Happy';型使用的时间为:"+(over-begin)+"毫秒");}}

原因是s=s+"Happy"操作在编译器期间被优化成"(s的值)Happy",而+=是在运行期间进行拼接操作并赋值。

 


参考资料

1、https://blog.csdn.net/weixin_41101173/article/details/79677982

2、https://www.cnblogs.com/dolphin0520/p/3778589.html

3、https://blog.csdn.net/danceinkeyboard/article/details/72858374

4、https://blog.csdn.net/jisuanjiguoba/article/details/82531868

http://www.jmfq.cn/news/5085775.html

相关文章:

  • 阿里巴巴怎么做公司网站/官网建站多少钱
  • 网站建设 沈阳/搜索引擎营销与seo优化
  • 大型网站开发项目合同/竞价外包代运营公司
  • 广州个性化网站建设/谷歌搜索网页版入口
  • 独立网站需要怎么做/在线培训系统app
  • 招聘做微信公众号网站维护/seo查询5118
  • 霍山做网站/企业邮箱
  • 做怎么网站收费/谷歌seo怎么做
  • 网络游戏网站网址大全/如何免费搭建自己的网站
  • 网站建设 人性的弱点/游戏推广平台有哪些
  • 慈溪市建设厅网站/在线生成个人网站
  • 专业提供网站建设服务/网站怎么做优化排名
  • bc源码 网站 搭建/电话号码宣传广告
  • 北京做网站设计招聘/网络营销推广方式包括
  • 伊春seo公司/百度首页排名优化哪家专业
  • 中纪委网站两学一做征文/谷歌账号注册
  • 网站怎么做付款平台/汕头seo外包机构
  • 贵州专业网站建设/免费推广网址
  • 长春网站建设/seo网站优化服务
  • axure做网站效果图步骤/全球搜索引擎市场份额
  • 制作网站付费软件/网站策划是什么
  • 电商网站制作流程图/上海抖音seo公司
  • 昆明哪些做网站建设的公司/移动慧生活app下载
  • 西安行业网站建设/网络营销到底是个啥
  • html 与wordpress/重庆seo霸屏
  • 企业网站及公众号建设方案/俄罗斯搜索引擎yandex官网入口
  • hefei 网站制作/关注公众号推广2元一个
  • 企业名录搜索网站/广州seo网站
  • 建网站做站长怎么赚钱/软文一般发布在哪些平台
  • 商城网站建设方案/东莞seo推广机构帖子