字符串,是由多个字符拼接成的文本值。字符串在存储上类似数组,不仅字符串的长度可取,而且每一位上的字符也可取,访问和操作数组一样。同时字符串也是对象!
字符串是常量,它们可以显示任何文本信息,字符串的值在创建之后不可更改。
//java中单引号是字符,双引号是字符串 "我是字符串","我长得比较帅气","123456789","一年分为四季"
延伸: java中字符串的变量是通过java.lang.String类来创建的,因此字符串变量也是一个对象。
注意: 声明一个字符串变量而不进行赋值的情况下,其默认值是null,在这样的情况下坚持去使用String类方法会报错。也就是空指针异常。
//语法:直接将字符串字面量赋值给String类型变量 String a = "世界很残酷,但我不能龟缩"; String b = "今天天气",c = "很不错哦!"; String str1,str2; str1 = "今天下雨了"; str2 = "今天下雨了";
分析:
当代码执行到 String a = " 世界很残酷,但我不能龟缩 ";时,JVM首先会去字符串常量池中检查有没有" 世界很残酷,但我不能龟缩 "字符串对象,如果有则不要再创建任何字符串对象,直接将池中的" 世界很残酷,但我不能龟缩 "这个对象地址返回,赋值给字符串常量。如果字符串池中没有,那么就在字符串池中创建" 世界很残酷,但我不能龟缩 "字符串对象,然后将池中的" 世界很残酷,但我不能龟缩 "这个对象的引用地址返回给字符串常量a,这样a就指向了池中" 世界很残酷,但我不能龟缩 "的字符串对象了。
当代码执行到 str1 = "今天下雨了" 时,JVM首先会去常量池检查是否 "今天下雨了" 字符串对象,如果不存在,则在字符串池中创建 "今天下雨了" 这个对象。然后将池中 "今天下雨了" 对象引用地址返回给字符串常量str1,这样str1就指向了字符串池中的 "今天下雨了" 对象了。如果存在,那么直接返回字符串池中的 "今天下雨了" 对象的引用地址给字符串常量str1,这样str1就指向了字符串池中的 "今天下雨了" 对象了。当代码执行到 str2 = "今天下雨了" 此时JVM去字符串池检索 "今天下雨了" 对象,发现已经存在了。那么直接返回 "今天下雨了" 对象的引用地址给字符串常量str2,这样一来str2就指向了字符串池中的 "今天下雨了" 的对象了。这样一来,str1和str2都指向了同一个字符串对象。
String str1,str2; str1 = "今天下雨了"; str2 = "今天下雨了"; //==判断是对象与对象的地址判断 System.out.println(str1 == str2); //true
注意: 当我们使用字符串常量时,JVM首先会检查字符串常量池;如果该字符串存在字符串常量池中,那么就直接返回常量池的对象引用。如果字符串常量不存在常量池中,就会实例化该字符串对象并将其放入到字符串常量池中。String字符串的不可更改性我们一定牢记,同时字符串常量池中也不可以出现二个一样的字符串
String a = "i love java"; String b = "i love java"; String c = new String("i love java");
通过上面的分析,我们明白字符串常量a和b都指向池中 **"i love java" 对象。这一点比较好理解,上面就强调了。字符串常量池中不可能出现一样的字符串对象。
当代码执行到 String c = new String("i love java") 这一行时,字符串对象是不通字符串常量创建的,而是通过 new 关键字创建的。
使用 new 创建字符串对象分析: 采用 new 创建字符串对象时,JVM首先会去字符串池中检查是否有这 "i love java" 字符串对象。如果有,则不在池中创建 "i love java" 对象,直接在堆中创建一个 "i love java" 字符串对象,然后将堆中 "i love java" 对象地址返回赋值给引用c,这样c就指向了堆中的 "i love java" 字符串对象了;如果没有,则首先在字符串池中创建 "i love java" 对象,然后再在堆中创建 "i love java" 字符串对象,然后将堆中的 "i love java" 字符串对象地址返回赋值给引用 c 。这样 c 就指向了堆中 "i love java" 对象了。
注意:new关键字一定会产生对象 "i love java" ,通过new关键字产生的对象是存储在堆中。上面代码应该产生了二个对象: 1.保存在堆中的 "i love java" ;2.保存在栈中的c; 。而java中根本就不存在二个一模一样的字符串对象,因此就可以分析得出堆中的 "i love java" 就是引用字符串池中的 "i love java" 对象,所以可以捋一个关系出来。c -> 堆中"i love java" -> 池中"i love java"
总结: 从上分析a、b、c、"i love java"是四个不同的对象,虽然c的创建在堆,但他的内部value是指向JVM字符串常量池中的"i love java"的value,因为最终构造字符串对象还是字符串常量"i love java"。
//new关键字新建一个字符串对象 String str1 = new String("zhangsan"); String str2 = new String("zhangsan"); System.out.println(str1 == str2);
执行代码,结果输出为:false
分析:不管是创建字符串对象还是其它对象,只要是通过 new 关键字创建出来的对象,都会在堆中创建一个新对象。虽然我们str1和str2的字符串常量都是"zhangsan",但str1和str2在堆中存在的是二个完全不相干的新对象。所以他们的结果为false.
//代码所在编译期就确定的情况 String str1 = "zhangsan"; String str2 = "zhangsan"; String str3 = "zhang" + "san"; System.out.println(str1 == str2); System.out.println(str2 == str3);
执行代码,输出结果为:true,true
str1和str2都是字符串常量"zhangsan"创建的,所以他们都是指向JVM字符串常量池中的同一个对象,同时他们在代码的编译期间就已经确定了。因此第一个输出一定是为true;当一个字符串由多个字符串常量连接而成,那么这个字符串一定也是一个字符串常量 ,因此str3也在编译期就已经被解析为一个字符串常量,同样str3也指向池中的"zhangsan"。那么str1=str2=str3输出为true。
//代码在编译时无法确定是否为字符串常量时 String str1 = "zhangsan"; String str2 = new String("zhangsan"); String str3 = "zhang" + new String("san"); //判断上面三个字符串对象,地址是不是一样的 System.out.println(str1 == str2); System.out.println(str2 == str3); System.out.println(str1 == str3);
执行代码,输出结果为:false,false,false
分析: 字符串常量在编译时就确定,ok之后就放入到池中。但使用new String()创建的对象就不能在编译期确定,所以不能直接放入到常量池中,它们有自己的地址空间那就是堆。
str1是字符串常量,编译期就能确定,所以是常量池中"zhangsan"的引用。str2是使用new关键字创建的,所以在编译期无法确定,只能在代码运行期被创建的新对象的地址引用。str3后一部分是new String("san");无法在编译期就确定,所以也是一个在运行期创建"zhangsan"对象的引用。
String str1 = "zhang"; String str2 = "san"; String str3 = str1 + str2; System.out.println(str3 == "zhangsan");
执行代码,输出结果为:false.
分析:str3是指向堆中的"zhangsan",而"zhangsan"是指向常量池中的对象,所以输出结果为false。
创建字符串对象总结:
a).java中的基本数据类型变量在使用 == 时, 比较是他们存储的直接“值”,而不是什么地址。
基本数据类型一共为:[byte,short,int,char,long,float,double,boolean]
b).但如果在引用类型(String)中使用,则比较的是他们把指向的对象的地址是否相同(也就是不是同一个对象)。
equals是Object类中的方法,所以只要继承了Object类都有equals方法,但java中的基本数据类型不能使用equals进行比较,因为基本数据类型比较的还是地址是否指向同一个对象。而我们String就重新写了equals方法,主要作用是用于比较二个字符串对象所存储的字符串是否相等。当然Double,Date,Integer这一些都有重写equals方法。比较的是内容!
public static void main(String[] args){ String str1 = "zhangsan"; String str2 = "zhangsan"; String str3 = "zhang" + new String("san"); System.out.println(str1 == str2); System.out.println(str2 == str3); //String中使用equals是比较字符串是否相等 System.out.println(str2.equals(str3)); }
执行代码,输出结果:true false true
//分析以下代码具体执行过程 public static void main(String[] args){ String s1 = "wo"; String s2 = "zhangsan"; String s3 = "da" + "haohao" + s1 + "shi" + "en" + s2; System.out.println(s3); }
在java中String使用 "+" 字符串连接符进行字符串连接,连接符最开始位置如果都是字符串常量,那么编译后尽可能多的将字符串常理连接起来。不管怎么样,代码是从最左边依次执行。模拟执行结果为: String s3 = new StringBuilder("dahaohao").append(s1).append("shi").append("en").append(s2).toString();
首先以"dahaohao"作为参数创建StringBuilder对象,然后依次进行append操作,最后调用toString()方法转换成String对象。记得只有最左边的字符串常量尽可能的多连接在一起,之后就没有这样的操作了。
所以看着很简单的操作其内部就完成了很多步骤。 "+" 进行多个字符串以及变量连接时,会产生一个StringBuilder对象和String对象。
主要是对字符串对象进行操作,长度、索引等
字符串对象有一个方法可以获得字符串对象长度,也就是由多少个char字符组成。
public static void main(String[] args){ String str1 = "中华人民共和国万岁"; String str2 = "中华人民共 和国万岁"; System.out.println(str1.length()); System.out.println(str2.length()); }
执行代码,输出结果为:9 10
注意:字符串对象中的length()方法与数组中的length属性都是用来获取长度,但String中的length()是成员方法;数组中的length属性是数组类的一个属性没有括号。
String类中有一个成员方法是charAt(int index)方法来获得指定索引的字符。
public static void main(String[] args){ String str = "我欲静思,佛魔无用。"; //创建String对象 //charAt(index); 语法: //str:是任意字符串对象 //index:str的对象的char索引,是int类型 char at = str.charAt(4); System.out.println("字符串中索引位置为4的字符是:" + at); }
子字符串是字符串对象组成的一部分,也就是被包含在字符串对象里。
public static void main(String[] args){ String str = "编程就像剑客,编得好叫大师。"; int size = str.indexOf('客'); System.out.println(size); //5 }
注意:String中的indexOf()方法返回的是搜索字符或字符串在字符串中首次出现的索引位置。如果没有检索到则返回-1,有就返回所在字符串中的索引位置。
startWith()和endsWith()方法分别用于判断字符串中是否以指定内容开始或结尾。这个方法返回值都是boolean类型
public static void main(String[] args){ //使用startWith和endsWith统计电器 String arr[] = {"美的电磁炉","海尔冰箱","格力空调","小米手机","海尔衣机","美的吸尘器","格力手机","海尔电热水器","海信液晶电视"}; int num1 = 0; //出现海尔数 int num2 = 0; //出现手机次数 for(int i = 0; i < arr.length; i++){ String str = arr[i]; if (str.startWith("海尔")){ num1++; } if(str.endsWith("手机")){ num2++; } } System.out.println("出现海尔次数:" + num1); System.out.println("出现手机次数:" + num2); }
将一个字符串对象转换成一个字符数组
public static void main(String[] args){ String str = "柳岸花明又一村,编程使我走向光明。"; //使用toCharArray()方法,直接把一个字符串对象转换成一个char数组 char c[] = str.toCharArray(); //循环打印出字符数组 for(int i = 0; i < c.length; i++){ System.out.println("数组的第" + i +"个元素为:"+c[i]); } }
String类有一个成员方式contains()方法,作用是用来检索字符串是否包含指定内容。如果包含就返回true,否则为false。
public static void main(String[] args){ String str = "斗罗大陆:唐三,小白,小荣"; //看你喜欢的唐三是否在其中 boolean r1 = str.contains("唐三"); boolean r2 = str.contains("唐三三"); System.out.println(r1); // true System.out.println(r2); //false }
substring()方法返回一个新字符串,它是此字符串的一个字符串。该子字符串从指定beginIndex处的字符开始,直到endIndex-1处的字符。
pubic static void main(String[] args){ String Num = "123456198002175890"; String str1 = Num.substring(6); System.out.println(str1); //198002175890 String str2 = Num.substring(6,10); System.out.println(str2); //1980 }
注意: substring有二种用法,一是只有一个参数,二是指定开始和结束索引。
String字符串对象有一个成员方法replace(),是可以实现指定的字符或者字符串替换成新的字符序列。replace()用法:
注意:replace()方法返回的是一个新字符串对象。如果在字符串没有找到指定内容,那么就将原来的字符串对象返回。
public static void main(String[] args){ String str = "我的帅气,就好像你永远不懂别人在想什么一样"; String restr = str.replace("就好像","就一定像"); System.out.println(str); System.out.println(restr); }
split()方法可根据给定的分隔符对字符串进行拆分,最后返回一个字符串数组。
public static void main(String[] args){ String str = "蒸羊羔,蒸熊掌,烧花鸭,腊肉,松花小肝"; String[] arr = str.split(","); //循环 for(String tmp : arr){ System.out.println(tmp); } }
public static void main(String[] args){ String str = "abc ABC"; //小写格式 System.out.println(str.toLowerCase()); //大写格式 System.out.println(str.topperCase()); //去除字符串二边空格 String str1 = " abc "; System.out.println(str1.trim()); }
这是String的加强版处理类,因为String是一个不可变常量;也就是变量被赋值创建时就不能修改。所以频繁赋值就会创建很的新字符串对象,这样很浪费内存。为了提高效率也就是拼接字符串,JAVA就有了StringBuilder这个类,它是一个可变对象,可以预分配缓冲区,这样往StringBuilder中新增字符时,就不会创建新的临时对象了。
下面列出了此类的几个常用方法:
(1)append()方法可用来将文本或对象的字符串表示形式添加到由当前 StringBuilder对象表示的字符串的结尾处。
(2)appendformat()方法将文本添加到 StringBuilder的结尾处,而且实现了IFormattable接口,因此可接受格式化部分中描述的标准格式字符串。 可 以使用此方法来自定义变量的格式并将这些值追加到StringBuilder的后面。
(3)insert()方法将字符串或对象添加到当前 StringBuilder中的指定位置。
(4)可以使用delete()方法从当前StringBuilder中移除指定数量的字符,移除过程从指定的从零开始的索引处开始。
(5)使用replace()方法,可以用另一个指定的字符来替换 StringBuilder对象内的字符。
(6)setCharAt()方法是将指定索引处的字符修改为自己想要的字符