`

让你更深入的了解String

    博客分类:
  • JAVA
阅读更多

1、"abc"与new String("abc");

  经常会问到的面试题:String s = new String("abc");创建了几个String Object?【如这里创建了多少对象? 和一道小小的面试题 】

  这个问题比较简单,涉及的知识点包括:

  引用变量与对象的区别;

  字符串文字"abc"是一个String对象;

  文字池[pool of literal strings]和堆[heap]中的字符串对象。

  一、引用变量与对象:除了一些早期的Java书籍和现在的垃圾书籍,人们都可以从中比较清楚地学习到两者的区别。A aa;语句声明一个类A的引用变量aa[我常常称之为句柄],而对象一般通过new创建。所以题目中s仅仅是一个引用变量,它不是对象。[ref 句柄、引用与对象]

  二、Java中所有的字符串文字[字符串常量]都是一个String的对象。有人[特别是C程序员]在一些场合喜欢把字符串"当作/看成"字符数组,这也没有办法,因为字符串与字符数组存在一些内在的联系。事实上,它与字符数组是两种完全不同的对象。

  System.out.println("Hello".length());

  char[] cc={'H','i'};

  System.out.println(cc.length);

  三、字符串对象的创建:由于字符串对象的大量使用[它是一个对象,一般而言对象总是在heap分配内存],Java中为了节省内存空间和运行 时间[如比较字符串时,==比equals()快],在编译阶段就把所有的字符串文字放到一个文字池[pool of literal strings]中,而运行时文字池成为常量池的一部分。文字池的好处,就是该池中所有相同的字符串常量被合并,只占用一个空间。我们知道,对两个引用变 量,使用==判断它们的值[引用]是否相等,即指向同一个对象:

  String s1 = "abc" ;

  String s2 = "abc" ;

  if( s1 == s2 ) System.out.println("s1,s2 refer to the same object");

  else System.out.println("trouble");

  这里的输出显示,两个字符串文字保存为一个对象。就是说,上面的代码只在pool中创建了一个String对象。

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

  String s1 = new String("abc") ;

  String s2 = new String("abc") ;

  if( s1 == s2 ){ //不会执行的语句}

  这时用==判断就可知,虽然两个对象的"内容"相同[equals()判断],但两个引用变量所持有的引用不同,

  BTW:上面的代码创建了几个String Object? [三个,pool中一个,heap中2个。]

  [Java2 认证考试学习指南 (第4版)( 英文版)p197-199有图解。]

  2、字符串的+运算和字符串转换

  字符串转换和串接是很基础的内容,因此我以为这个问题简直就是送分题。事实上,我自己就答错了。

  String str = new String("jf"); // jf是接分

  str = 1+2+str+3+4;

  一共创建了多少String的对象?[我开始的答案:5个。jf、new、3jf、3jf3、3jf34]

  首先看JLS的有关论述:

  一、字符串转换的环境[JLS 5.4 String Conversion]

  字符串转换环境仅仅指使用双元的+运算符的情况,其中一个操作数是一个String对象。在这一特定情形下,另一操作数转换成String,表达式的结果是这两个String的串接。

  二、串接运算符[JLS 15.18.1 String Concatenation Operator + ]

  如果一个操作数/表达式是String类型,则另一个操作数在运行时转换成一个String对象,并两者串接。此时,任何类型都可以转换成String。[这里,我漏掉了"3"和"4"]

  如果是基本数据类型,则如同首先转换成其包装类对象,如int x视为转换成Integer(x)。

  现在就全部统一到引用类型向String的转换了。这种转换如同[as if]调用该对象的无参数toString方法。[如果是null则转换成"null"]。因为toString方法在Object中定义,故所有的类都 有该方法,而且Boolean, Character, Integer, Long, Float, Double, and String改写了该方法。

  关于+是串接还是加法,由操作数决定。1+2+str+3+4 就很容易知道是"3jf34"。[BTW :在JLS的15.18.1.3中举的一个jocular little example,真的很无趣。]

  下面的例子测试了改写toString方法的情况.。

  class A

  { int i = 10;

  public static void main(String []args)

  { String str = new String("jf");

  str += new A();

  System.out.print(str);

  }

  public String toString(){ return " a.i ="+i+"\n"; }

  }

  三、字符串转换的优化

  按照上述说法,str = 1+2+str+3+4;语句似乎应该就应该生成5个String对象:

  1+2 =3,then 3→Integer(3)→"3" in pool? [假设如此]

  "3"+str(in heap) = "3jf" (in heap)

  "3jf" +3 ,first 3→Integer(3)→"3" in pool? [则不创建] then "3jf3"

  "3jf3"+4 create "4" in pool

  then "3jf34"

  这里我并不清楚3、4转换成字符串后是否在池中,所以上述结果仍然是猜测。

  为了减少创建中间过渡性的字符串对象,提高反复进行串接运算时的性能,a Java compiler可以使用StringBuffer或者类似的技术,或者把转换与串接合并成一步。例如:对于 a + b + c ,Java编译器就可以将它视为[as if]

  new StringBuffer().append(a).append(b).append(c).toString();

  注意,对于基本类型和引用类型,在append(a)过程中仍然要先将参数转换,从这个观点看,str = 1+2+str+3+4;创建的字符串可能是"3"、"4"和"3jf34"[以及一个StringBuffer对象]。

  现在我仍然不知道怎么回答str = 1+2+str+3+4;创建了多少String的对象,。或许,这个问题不需要过于研究,至少SCJP不会考它。

  3、这又不同:str = "3"+"jf"+"3"+"4";

  如果是一个完全由字符串文字组成的表达式,则在编译时,已经被优化而不会在运行时创建中间字符串。测试代码如下:

  String str1 ="3jf34";

  String str2 ="3"+"jf"+"3"+"4";

  if(str1 == str2) { System.out.println("str1 == str2"); }

  else { System.out.println("think again"); }

  if(str2.equals(str1)) System.out.println("yet str2.equals(str1)");

  可见,str1与str2指向同一个对象,这个对象在pool中。所有遵循Java Language Spec的编译器都必须在编译时对constant expressions 进行简化。JLS规定:Strings computed by constant expressions (?15.28) are computed at compile time and then treated as if they were literals.

  对于String str2 ="3"+"jf"+"3"+"4";我们说仅仅创建一个对象。注意,“创建多少对象”的讨论是说运行时创建多少对象。

  BTW:编译时优化

  String x = "aaa " + "bbb ";

  if (false) { x = x + "ccc "; }

  x += "ddd ";

  等价于: String x = "aaa bbb "; x = x + "ddd ";

  //这个地方我自己进行了编译,不过和他的结论不一样,好像当用x+="ddd"的时候和直接的x="aaa"+"bbb"+"ddd" 不同,但是具体为什么我也不清楚,正在研究中。。。

  4、不变类

  String对象是不可改变的(immutable)。有人对str = 1+2+str+3+4;语句提出疑问,怎么str的内容可以改变?其实仍然是因为不清楚:引用变量与对象的区别。str仅仅是引用变量,它的值??它持 有的引用可以改变。你不停地创建新对象,我就不断地改变指向。[参考TIJ的Read-only classes。]

  不变类的关键是,对于对象的所有操作都不可能改变原来的对象[只要需要,就返回一个改变了的新对象]。这就保证了对象不可改变。为什么要将一个类设计成不变类?有一个OOD设计的原则:Law of Demeter。其广义解读是:

  使用不变类。只要有可能,类应当设计为不变类。

分享到:
评论

相关推荐

    深入了解java 中的String

    深入了解java 中的String 1、String类是final的,不可被继承。public final class String。 2、String类是的本质是字符数组char[], 并且其值不可改变。private final char value[]; 然后打开String类的API文档,...

    深入了解C#的String类.zip

    C#语言和SQL Server数据库技术 第四章深入了解C#的String类的教学演示案例上机练习参考答案课后作业参考答案 相关示例提供

    《深入学习c++string》2.1版

    3.2 更安全的C字符串函数 24 3.2.1 简述 24 3.2.2 简单实例 24 3.2.3 定制 24 3.2.4 兼容 24 3.3 通用字串函数 24 3.3.1 简述 24 3.3.2 简单实例 24 3.3.3 映射表 24 3.4 API级的字符串处理 24 3.4.1 简述 24 3.4.2 ...

    神奇的PHP String(深入剖析)

    对PHP String的深入了解与研究。

    深入了解java中的String-字符串(csdn)————程序.pdf

    深入了解java中的String-字符串(csdn)————程序

    深入解析String类:掌握Java中字符串处理的关键方法.zip

    string类的常用方法在Java编程中,String类无疑是我们最常用到的一个类。无论是用户输入、文件读取还是网络传输,字符串操作无处不在。...本篇博文将带你深入了解String类的核心方法,并通过实例演示它们的用法。

    C++中string类的模拟实现

    该资源有助于C++学习者从实现原理的层面进一步了解string类,为后续对string类灵活使用打下一个良好的基础;C++库中的string类接口较多,读者也可在此资源的基础上继续实现相关接口,并编写相应的测试代码进行测试。

    深入了解java中的string对象

    主要介绍了java中的string对象,String对象是Java中使用最频繁的对象之一,所以Java开发者们也在不断地对String对象的实现进行优化,以便提升String对象的性能。对此感兴趣的朋友跟随小编一起看看吧

    深入了解Java中String、Char和Int之间的相互转换

    主要介绍了深入了解Java中String、Char和Int之间的相互转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,,需要的朋友可以参考下

    C++ string替换指定字符实例代码

    不过只要再深入了解一下STL,就可以在变易算法中找到解决方案——使用#include中的replace算法即可。 测试代码如下: #include #include<string> #include using namespace std; int main() { string str="123/...

    STL 的string类怎么啦

    那时,我不得不研究那根本不是给人看的SGI出品的string类的源码,代码的可读性几乎为零,而且随着了解越深入,就越觉得C++的世界中到处都是陷阱和缺陷。越来越觉得有时候那些类并不像自己所想象

    C++中的string类(C++字符串)入门完全攻略

    前言 string 类是 STL 中 basic_string 模板实例化得到的模板类。...要想更深入地了解 string 类,还要阅读 C++ 的参考手册或编译器自带的联机资料。对于前面介绍过的字符串处理的内容,这里不再重复说明。 1.

    代码类C++Stirng 类的代码帮助更深的了解c++函数

    C++ string 类的代码 关于构造函数、析构函数、赋值函数、复制函数等等!

    简单学生信息管理系统简洁清晰,链表;

    在空余时间写出了这个系统,让我对c++的理解更深了一层;简单的学生信息管理系统,利用C++编写。拥有增、删、查、显示、功能。 代码简洁清晰步骤清晰能让你更加 了解c++代码运用,推荐使用VS2019或以上版本的编译器...

    java 面对对象编程.pdf.zip

    深拷贝和浅拷贝区别了解吗?什么是引用拷贝? Java 常见类 Object Object 类的常见方法有哪些? == 和 equals() 的区别 hashCode() 有什么用? 为什么要有 hashCode? 为什么重写 equals() 时必须重写 hashCode() ...

    javascript正则表达式和字符串RegExp and String(二)

    我认为,在学习一门编程语言的过程中,字符串、数组、容器是非常重要的部分,为了提高编程效率,我通常会对字符串、数组以及容器作深入的学习,详细了解相关特点及对应的API。这篇文章是针对javascript字符串学习写...

    积分java源码-java-data-types-string-apis-java-se-11:java-data-types-string-

    认证路径专为帮助您完成本课程的考试而设计,将涵盖多个主题,包括深入了解原始类型和变量类型、如何使用所有 Java 运算符以及一些数学 API 使用原始说唱歌手,例如 integer 和 double。 对变量命名和其他规则(包括...

    C# 2.0中泛型编程初级入门教程.pdf

    本文讨论泛型使用的一般问题,比如为什么要使用泛型、泛型的编写方法、泛型中数据类型的约束、泛型 中静态成员使用要注意的问题、泛型中方法重载的问、泛型方法等,通过这些...读完本篇文章,你会对泛型有更深的了解。

    Python基础教程-第4章-Python-数据类型.pptx

    Python 基础教程 第4章 Python 数据类型 Python基础教程-第4章-Python-数据类型全文共70页,当前为第1页。 Python 有 6 个主要的标准数据类型: Number(数字);...了解深复制与浅复制的概念及操作 8.了解推导式的概

    深入java虚拟机第二版

    深入java虚拟机第二版 第1章 Java体系结构介绍 1.1 为什么使用Java 1.2 网络带来的挑战和机遇 1.3 体系结构 1.3.1 Java虚拟机 1.3.2 类装载器的体系结构 1.3.3 Java class文件 1.3.4 Java API 1.3.5 ...

Global site tag (gtag.js) - Google Analytics