让你更深入的了解String

旗袍小姐920

旗袍小姐920

2016-02-19 20:26

下面图老师小编要向大家介绍下让你更深入的了解String,看起来复杂实则是简单的,掌握好技巧就OK,喜欢就赶紧收藏起来吧!

  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的串接。

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

  二、串接运算符[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+""; }
  }

   

  三、字符串转换的优化

  按照上述说法,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。其广义解读是:

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

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)
展开更多 50%)
分享

猜你喜欢

让你更深入的了解String

编程语言 网络编程
让你更深入的了解String

别怪我的狠心,我只是不想让你受伤更深.

电脑入门
别怪我的狠心,我只是不想让你受伤更深.

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

让你了解生地

营养价值
让你了解生地

让你了解乌梅

饮食禁忌
让你了解乌梅

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

让你了解核桃

营养价值
让你了解核桃

让你了解田七

中医保健 中医养生 中草药
让你了解田七

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

走出abstract class与interface的困惑

走出abstract class与interface的困惑

引入CSS样式的五种方式

引入CSS样式的五种方式
下拉加载更多内容 ↓