前不久刚看完这一章,然而这遗忘速度实在是不能忍,既然总是遗忘,那么老衲就和你磨上一磨。

1.字符串基础

先说字符串吧,看例1:

 String a = "abc";
String b = "abc";
a==b; //true
a.equals(b) //true

再来看看例2:

String a = new String("abc");
String b = new String("abc");
a==b; //false
a.equals(b); //true

在例1中,"abc"是放在常量池(Const pool)中的,所以虽然a,b都等于"abc",但是内存中只有一份副本,所以"==" 返回true。"abc"是编译期常量,编译时已经能够确定它的值,在编译好的class文件中,它已经在String Pool中了, String a = "abc"; 会在String Pool中查找等于"abc"的字符串(用equals),若存在就把引用返回,若不存在就会创建一个"abc"放在String Pool中,然后把引用返回。

在例2中,new方法决定了两个不同的String "abc"被创建放在了内存heap区,分别被a,b指向,因此,"==" 返回了false;这里要注意的一点是:Const Pool存储在Method Area中,而不是堆中。所以,我们可以看看例3:

 String s1 = new String("aaa777");
String s2 = "aaa777";
System.out.println(s1==s2);//结果为false

在Java中,使用new关键字会创建一个新对象,在本例中,不管在String Pool中是否已经有值相同的对象,都会创建一个新的String对象存储在heap中,然后返回其引用。s2指向的对象存储在String Pool中,他们肯定不是同一个对象,只不过存储的字符串相同罢了,所以返回的结果必然是false。

下面我们再来延伸一下:

String s = "a" + "b" + "c" + "d" + "e";

这里一共创建了几个对象?A.没有创建 B.1个对象 C.2个对象 D.3个对象

答案是:B   要注意的是,赋值语句后面部分的"a"、"b"、"c"、"d"、"e"都是常量,对于常量,编译时就直接存储他们的字面值,而不是它们的引用,在编译时就直接将它们连接的结果提取出来变成了"abc"。关于这个String类重载的连接符,后面我们还会讲到,这里先点到为止。再说一点,String使用private final char value[]来实现字符串的存储,也就是说String对象创建之后,就不能再修改此对象中存储的字符串内容,就是因为如此,才说String类型是不可变的(immutable)。

再看例4:

 String s1 = new String("aaa777");
s1 = s1.intern();
String s2 = "aaa777";
System.out.println(s1==s2);

你猜一猜这个最终的执行结果会是什么?是true!没错,是true!

当调用intern方法时,如果String Pool中已经包含一个等于此String对象的字符串(用equals确定),则返回池中的字符串,否则将此String对象添加到池中,并返回此String对象在String Pool中的引用。由于执行了 s1 = s1.intern(); ,会使s1指向String Pool中值为"aaa777"的字符串对象,s2也指向了同样的对象,所以结果为true.

例5:

 String s1 = new String("777");
String s2 = "aaa777";
String s3 = "aaa"+"777";
String s4 = "aaa" + s1;
System.out.println(s2==s3); //true
System.out.println(s2==s4); //false
System.out.println(s2==s4.intern()); //true

显然,行5和行7结果就不需要我来讲了,问题在行6。为什么行6的结果是false呢?由于s1是变量,在编译期不能确定它的值是多少,所以会在执行的时候创建一个新的String对象存储到heap中,然后赋值给s4!注意,是heap中,而s2在Const Pool中,显然s2和s4的引用值自然是不相等的。

好了,字符串基础快讲完了,有点长,最后我们再看一个函数结束吧~

 String str = "ABCDEFGH";
String str1 = str.substring(3,5);
System.out.println(str1);

猜猜结果是多少?"DEF"吗?差点对=。=  这里要注意啊,java中的substring是前包括后不包括的,所以应该是"DE"。

2.StringBuffer

例1:

 String result = "hello" + "world";
StringBuffer result = new StringBuffer.append("hello").append("world");

行1的效率好于行2,这是因为JVM会进行如下处理:

  • 将result字符串进行"hello"+"world"处理,然后才赋值给result,只开辟了一次内存段。
  • 编译StringBuffer后还要进行append处理,开辟了一次内存,扩展了2次,花的时间要长一些。

例2:

 public String getString(String s1,String s2){
return s1+s2;
} public String getString(String s1,String s2){
return new StringBuffer().append(s1).append(s2);
}

这两个的效率是一样的,都是先开辟一个内存段,再合并(扩展)内存,所以两者执行的过程是一致,效率相当。

例3:

(1)String s = "s1";
s+="s2";
s+="s3";
(2) StringBuffer s = new StringBuffer().append("s1").append("s2").append("s3");

(2)的效率好于(1),因为String是不可变对象,每次"+="操作都会构造新的String对象,实际上是另外创建了一个对象,而原来指向的那个对象就成了垃圾,比如如下代码:

 String tmp = "";
for(int i =0;i<9999;tmp += "x"){}

一个循环就产生了n个对象,从而造成内存和时间的浪费。

例4:

 (1)StringBuffer s = new StringBuffer();
for(int i=0;i<50000;i++){
s.append("hello");
}
(2)StringBuffer s = new StringBuffer(250000);
for(int i=0;i<50000;i++){
s.append("hello");
}

(2)的效率好于(1),因为StringBuffer内部实现的是char数组,默认初始化长度为16,每当字符串长度大于char数组长度的时候,JVM会构造更大的新数组,并将原先的数组复制到新数组,(2)避免了数组复制的开销。

最后再看一个例子:

例5,以下程序创建了几个对象?A. 4 B. 3 C. 5 D. 6

 String A,B,C;
A = "a";
B = "b";
A = A + B;
StringBuffer D = new StringBuffer("abc");
D = D.append("567");

首先,我们先搞清几个概念:

  • 引用变量与对象。A aa; 语句声明一个类A的引用变量aa(常称为句柄),而对象一般通过new创建。所以题目中D仅仅是一个引用变量,他不是对象。而字符串"abc"是一个String对象
  • Java中所有的字符串文字(字符串常量)都是一个String的对象。有人在一些场合喜欢把字符串当做字符数组,因为字符串与字符数组存在一些内在的联系。事实上,它与字符数组是两种完全不同的对象。如System.out.println("Hello".length()); 这里length()显然是对象的方法,而char[] cc = {'H','i'};System.out.println(cc.length); 这里的cc.length则是数组的属性,要注意区分。

字符串对象的创建。由于字符串对象的大量的使用,Java中为了节省内存空间和运行时间,在编译阶段就把所有的字符串文字放到一个文字池(pool of literal strings)中,而运行时文字池成为常量池的一部分。文字池的好处就是该池中所有相同的字符串常量被合并,只占用一个空间。我们来看一段代码:

 String s1 = new String("abc");
String s2 = new String("abc");

String s1 = new String("abc");语句,这里"abc"本身就是pool中的一个对象,而在运行时执行new String()时,将pool中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s持有。这条语句就创建了2个String对象。于是,上面的两行代码创建了3个对象,pool中一个,heap中2个!

OK,我们现在来对例5进行一下解析。

StringBuffer D = new StringBuffer("abc"); 产生了两个对象,"abc"本身与经过new创建出来的不是一个对象。 A=A+B; 此处创建了一个对象,并由引用A来引用,那么原来A所指向的对象就成为了垃圾,被回收。StringBuffer的特点是改变对象本身而不是创建新的对象,因此,此处 D= D.append("567"); 都是对同一个对象进行处理。所以整个例5一共创建了1+1+1+2=5个对象,答案是C

3.正则表达式

例1: String s = "32fdsfd8fds0fdsf9323k32k" ,从中找出3280932332,你会怎么做?

一般做字符串替换,我们能想到的一般方法都是正则表达式。所以可以这样: String a = s.replaceAll("[^0-9]",""); ,"[^0-9]"是正则表达式,表示除了0到9以外的字符,这条代码的意思是将s中所有非0-9的字符替换为空串。

例2: String str = "2006-04-15 02:31:04" ,要把这个串变成20060415023104,你会怎么做?

首先,这个简单的任务可以用最笨的方法:

str = str.replaceAll("-","");str = str.replaceAll(":","");str = str.replaceAll(" ",""); ,不过这有点太low逼了,看下面的方法:

 class Test{
public static void main(String[] args){
String str = "2006-04-15 02:31:04";
String str2 = "";
String[] result = str.split("\\D");
for(int i=0;i<result;i++){
System.out.print(result[i]);
str2 += result[i];
}
System.out.println(str2);
}
}

这里"\\D"表示非数字字符。

《Java程序猿面试宝典》之字符串的更多相关文章

  1. 《Java程序猿面试笔试宝典》之字符串创建与存储的机制是什么

    在Java语言中.字符串起着非常关键的数据.字符串的声明与初始化主要有例如以下两种情况:(1) 对于String s1=new String("abc")语句与String s2= ...

  2. 《Java程序猿面试笔试宝典》之Java与C/C++有什么异同

    Java与C++都是面向对象语言,都使用了面向对象思想(比如封装.继承.多态等),因为面向对象有很多非常好的特性(继承.组合等),使得二者都有非常好的可重用性. 须要注意的是,二者并不是全然一样,以下 ...

  3. 《Java程序猿面试笔试宝典》之组合与继承有什么差别

    组合和继承是面向对象中两种代码复用的方式. 组合是指在新类里面创建原有类的对象,反复利用已有类的功能.继承是面向对象的主要特性之中的一个,它同意设计人员依据其他类的实现来定义一个类的实现. 组合和继承 ...

  4. 《Java程序猿面试笔试宝典》之Java程序初始化的顺序是如何的

    在Java语言中.当实例化对象时.对象所在类的全部成员变量首先要进行初始化,仅仅有当全部类成员完毕初始化后,才会调用对象所在类的构造函数创建对象.    Java程序的初始化一般遵循以下三个原则(以下 ...

  5. 《Java程序猿面试笔试宝典》之 什么是AOP

    AOP(Aspect-Oriented Programming.面向切面编程)是对面向对象开发的一种补充,它同意开发者在不改变原来模型的基础上动态地改动模型从而满足新的需求.比如.在不改变原来业务逻辑 ...

  6. 《Java程序猿面试笔试宝典》之volatile有什么作用

    在由Java语言编写的程序中.有时候为了提高程序的执行效率,编译器会自己主动对其进行优化,把经常被訪问的变量缓存起来,程序在读取这个变量的时候有可能会直接从缓存(比如寄存器)中来读取这个值.而不会去内 ...

  7. GEEK学习笔记— —程序猿面试宝典笔记(二)

    所谓笔记,就是比較个人的东西,把个人认为有点意思的东西记录下来~~ 程序猿面试宝典笔记(一)基本概念 程序猿面试宝典笔记(二)预处理.const和sizeof 程序猿面试宝典笔记(三)auto_ptr ...

  8. GEEK学习笔记— —程序猿面试宝典笔记(三)

    所谓笔记,就是比較个人的东西,把个人认为有点意思的东西记录下来~~ 程序猿面试宝典笔记(一)基本概念 程序猿面试宝典笔记(二)预处理.const和sizeof 程序猿面试宝典笔记(三)auto_ptr ...

  9. 《JAVA 程序员面试宝典(第四版)》读书笔记之前言

    工作五年了一直在小的软件公司混,总感觉自己的专业知识没有太大的提升.当然了中间也换了一两家公司,面试的公司就很多家,总感觉正规的软件公司(无论大小)对于基础知识的考核都非常重视,而不管你说你之前服务过 ...

随机推荐

  1. Linux 环境下Web环境搭建————ActiveMQ

    1.下载安装包http://activemq.apache.org/activemq-5143-release.html 2.解压至指定目录 bin目录下为执行脚本 (脚本无法执行需要修改权限(chm ...

  2. Virtualbox+Ubuntu安装,VERR_VMX_MSR_ALL_VMX_DISABLED解决

    学习链接:基于VirtualBox虚拟机安装Ubuntu图文教程--娄老师 启动虚拟机遇到的问题:BIOS中VT-x在所有CPU模式下被禁用(VERR_VMX_MSR_ALL_VMX_DISABLED ...

  3. eg_5

    问题描述:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符. 例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.” ...

  4. WinForm中DataGridView的快速查找及将指定行显示到第一行

    /// <summary> /// 快速在已绑定的列表查询车辆 /// </summary> /// <param name="sender"> ...

  5. WinForm中DataGridView的全选与取消全选

    /// <summary> /// 全选 /// </summary> private void SelectAll() { //结束列表的编辑状态,否则可能无法改变Check ...

  6. keil c51笔记

    第一章 Keil C51开发系统基本知识 第一节 系统概述 Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上.结构性.可读性. ...

  7. C++判断char*的指向

    char *a = "Peter"; char b[] = "Peter"; ]; strcpy_s(c, , "Peter"); 这里a指 ...

  8. 获取SQL Server中连接的客户端IP地址[转]

    有时候需要获取连接到SQL Server服务器上的客户端IP地址,用什么办法呢? SELECT *FROM sys.dm_exec_connections WHERE session_id = @@S ...

  9. 面试问题总结二(技术能力-PHP)----Ⅰ

    1.你都做过什么项目? 答:第一份实习工作接触的项目是CRM 销售管理系统,一款用JSP语言开发的进销存管理系统.第一份正式工作是一款主打高质量图片社交社区网站项目,“美啦周末”(后改型为”聊会儿”) ...

  10. Hibernate 之主键生成策略小总结

    主键生成策略大致分两种: 手工控制策略 自动生成策略[框架自动生成和数据库自动生成] 手工控制策略: assigned:类型是任意的,需要在 save() 到数据库前,编码人员手工设置主键值,也就是调 ...