A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黄玉昆 黑马帝   /  2013-2-10 11:24  /  1960 人查看  /  3 人回复  /   2 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 黄玉昆 于 2013-2-10 11:34 编辑

下面是我通过翻看书籍和在网上找的一些资料,加了一些自己的理解,对字符串String一些浅显认识,希望对大家有所帮助
一、定义:
1、从概念上讲,java字符串就是Unicode字符序列。每个用双引号括起来的字符串都是String类的一个实例。Java字符串由char序列组成,字符数据类型是一个采用UTF-16的编码表示Unicode代码点的代码单元。(大多数的常用Unicode字符使用一个代码单元就可以表示,而付诸字符需要一对代码单元表示。具体内容,请自行查阅相关资料或者百度,本人不在此赘述了。)
2、格式:
  1. String a = ”abc”;//存储在StringPool中
  2. String b = new String(”abc”)://存储在堆内存中
复制代码
3StringPool(字符串池):有一个存放字符串的公共存储池,称为StringPool,即字符串池。字符变量指向存储池中的相应位置。如果是通过复制一个字符串变量,原始的字符串和复制的字符串将共享这个相同的字符串。
二、特点:
1String是一种特殊的数据类型,可创建对象。
2、通过String创建的对象分别可存在于字符串池(StringPool)和堆内存中
3String是一个final的类型,即不可被继承修改,一经生成不可改变。
4StringPool中的数据可共享,即两个引用变量可指向同一个字符串池中的字符串
5Java中的任何对象都可写成字符串的形式。
字符串不可变的原因:
a. 可以想得出,每种固定的东西是不会改变的,1就是1,也就是说你若想改变,只得改变这个引用变量所指向的地址。
b. 编译器可以让字符串共享数据。所以不必改变字符串,直接改变变量即可。
c. java的开发者认为共享数据的效率要远远胜于提取、拼接字符串的效率。程序中对字符串的修改操作很少,更多的是对字符串进行比较
(例外:将源自于文件或键盘的单个字符或较短的字符串汇集成字符串。具体在下面会说到。)
三、构造字符串上面也提到了:
按键或者来自文件中的单词。采用字符串连接的方式达到此目的的效率是十分低的,每次连接字符串,都会构建一个新的String对象,既降低了效率,又占用大量的空间。通过使用StringBuilder类局可以避免这个问题。
构建格式:
  1. StringBuilder bul = new StringBuilder();
复制代码
在构建字符串时就调用toString方法,可以得到一个String对象,其中包含构造器中的字符序列。如果要在字符串中“添加”一些内容,则可以使用append方法。例子:
  1. StringBuilder result = new StringBuilder();
  2.               for (int i = 0; i <  10; i++)
  3.               {
  4.                      result.append("a");
  5.                      result.append(" ");
  6.               }
  7.               System.out.println(result.toString());
复制代码
关于StringBuilder的内容,我找了一些资料,如果想了解更多,可以参阅:http://blog.csdn.net/shengfeixiang/article/details/8577823
四、字符串方法:
下面给大家介绍几个比较常用的关于字符串的方法;如果还想了解更多关于字符串的方法,可以查看字符串API
1substring(a,b) -- 获得字符串的子串:
String类的方法substring可以从一个较大的字符串提取出一个子串。方法的中a代表字符串的其实位置(第一个是0),获得s.substring(a,b)的长度是b-a。例如:
  1. String s= ”Hello”;
  2. String str = s.substring(0,3);//得到str = ”Hel”
复制代码
2length -- 获得字符串的长度:
length方法返回给定字符串的长度:
  1. String s = ”Hello”;
  2. int n = s.length();//值为5
复制代码
3、查找字符串及位置:
1charAt(int a)方法:调用该方法将返回当前对象字符串中位置为a的中的即字符。
  1. char first =  s.charAt(0);//first值为’H’
  2. char last =  s.charAt(5);//first值为’o’
复制代码
2indexof()方法:如果想查找某些或某个字符串在语句或文章中的位置,可使用此方法,如果找到了这句话,引用变量将等于该文本的起始位置,否则返回-1.如:
  1. String dream = ” I have a dream that one day every valley shall be exalted”;//这是马丁路德金演讲中的一句话
  2. int position = dream.indexof(” Every valley shall be exalted”);//返回-1,因为e大写了
复制代码
3)转换字符串大小写:Java是严格区分大小写的,若是想识别两个文本的值是否相等,可以使用这两个方法,如:
(1) toUpperCase() :将所有字符串转换成大写
(2) toLowerCase() :将所有字符串转换成小写
  1. String m = ”Hello”;
  2. String temp = m.toUpperCase();//结果为HELLO
复制代码
4+  -- 字符串的拼接:
Java中使用 + 连接(拼接)两个字符串,+ 是按照给定的顺序将两个字符串拼接起来的。当一个字符串和一个非字符串进行拼接时,后者被转换成字符串(任何一个java对象都可以转换成字符串。)例如:
  1. String m = ”Expletive”;
  2. String n = ”add”;
  3. int num = 24;
  4. String pj = m + n + num; //pj得到的结果为:”” Expletiveadd24”
复制代码
一般多用于输出语句中:System.out.println(”Thename is ” + name);
5intern()方法
该方法返回是始终都是StringPool中的对象。和String m = ”Hello”声明代码的效果实际上是一样的,使用intern返回的始终是StringPool中的对象。比如你首先使用String s = newString("abc")声明一个变量,然后判断s == s.intern()的话,那么会得到一个false,原因就是因为s是分配在堆中的一个新对象。
由于字数限制,下面还有关于总结的内容:



3 个回复

倒序浏览
6、字符串的比较
1)概述:Object这个根类中,存在一个equals(Oject obj)的方法,指示其他某个对象是否与此对象相等。但是在String的方法中也有一个equals的方法,你查看API文档就会发现:根类Object中的equals方法被String中的equals方法覆盖了,它是将此字符串与指定的对象比较。当且仅当该参数不为 null,并且是与此对象表示相同字符序列的String对象时,结果才为 true。表达式为:x.equals(y)
如果字符串x和字符串y相等,则返回true,否则放回false。需要注意的是,xy可以使字符串变量,也可以是字符串常量,如这样的写法也是合法的:”Hello”.equals(str)
2)检测两字符串是否相等:
(1) equalsIgnoreCase方法:要想检测两个字符串是否相等,而且不区分大小写,则可以使用此方法。使用==运算符,检测的是指向字符串池中同一个字符串的两个引用变量是否相等。可以思考一下,只有字符串常量是真正实现共享的,如果用+或者substring这样的拼接等操作产生的结果并不是共享的。而是在StringPool又创建了一个新的字符串对象。
(2)比较:
第一、String s = "abc”在执行这句代码的时候,JVM会首先查询StringPool,如果在该StringPool中已经存在相应的String实例了,那么将不会在堆中分配相应的内存来生成一个String对象,所以在代码中多次使用上面的声明来声明的变量实际指向的是同一个对象(那么当然就是相同的数据了)。现在来说一下JVM查找的时候没有找到相应的String对象的情况,这时JVM会在StringPool中生成相应的对象,但是并不会在堆中生成相应的对象,所以只要使用上面的代码声明,堆中将始终不会生成新的String对象。
第二、String str = new String(”abc”):要是比较这样定义格式的字符串,就需要使用equals方法了,上面也说到了,String类对Objectequals进行了覆盖了,所以String类是有自己比较字符串的方法的。
只有使用new创建一个对象,那么就会在堆内存中开辟一块空间存放这个数据。看下面的代码:
  1. String s1 = "abc";
  2. String s2 = new String("abc");
  3. String s3 = new String("abc");
  4. String s4= s2;
  5. s1==s2;//false,不是同一个对象
  6. //下面都是比较的字符串这个值,即数据
  7. s1.equals(s2);// true
  8. s2.equals(s3);//true
  9. s2.equals(s4);//true
复制代码
第三、需要补充一点:对于下面的代码,有一点要说的:就是无论String s2 = new String("abc")s1前面写还是后面写,s2都会检查StringPool中是否有"abc",若有,就直接在堆内存中创建一个对象;若没有,则要先在StringPool中创建"abc"后,再在堆内存中创建一个对象。
  1. String s1 = "abc";
  2. String s2 = new String("abc");
复制代码
注意:选择用==运算符比较两个字符串总不是太好的方法,否则StringAPI文档也不会覆盖Object中的equals方法了。所以最好不要使用==运算符检测两个字符串是否相等,因为这个运算符只能确定两个字符串是否放在同一个位置上。对于两个对象,==运算符检测的结果当然为false了。也就是说一般检测下面所定义格式的字符串:
  1. String greet = "Hello";
  2. System.out.println(greet == "Hello");//true
  3. System.out.println(greet.substring(0,3) == "Hel");//false
复制代码
回复 使用道具 举报
黄玉昆 发表于 2013-2-10 11:25
6、字符串的比较:1)概述:在Object这个根类中,存在一个equals(Oject obj)的方法,指示其他某个对象是否 ...

我自己画了幅图,不知理解对否:


String赋值图.PNG (36.52 KB, 下载次数: 43)

String赋值图.PNG
回复 使用道具 举报
本帖最后由 toShareBeauty 于 2013-7-14 15:55 编辑
黄玉昆 发表于 2013-2-10 13:53
我自己画了幅图,不知理解对否:

据我理解,String 的常量池,其实是 String 类加载到 JVM 方法区以后,String 这个类的字节码的常量池,和其他类常量池一样。里面主要有类使用到的常量和类、接口引用的符合引用,在链接阶段,这些符号引用会被替换为直接引用。但是据我所知常量池里面可以保存的常量只能是 JVM 内部支持的数据类型,即8种基本数据类型、reference类型和数组类型引用,对象这种不能保存在常量池吧,保存在常量池的是对象的引用吧。
以上说法有误,常量池支持 String 以二进制格式存储,在 utf-8 段中。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马