String类和常量池的概念
1、String类的概念(重点)
java.lang.String类用于描述字符串,Java程序中所有的字符串字面值(直接量)都可以使用该类的对象加以描
述,如:"abc"。
总结:
1、该类由final关键字修饰,表示该类不能被继承。
2、exends object 继承自对象,所以前面章节中重写的equals/hashcode/tostring都继承下来了,而且本类还实现了一些接口。
3、从jdk1.9开始该类的底层不使用char[]来存储数据,而是改成 byte[]加上编码标记,从而(实际上目的)节约了一
些空间。
该类描述的字符串内容是个常量不可更改,因此可以被共享使用。
如:
String str1 = “abc”; - 其中"abc"这个字符串是个常量不可改变。
str1 = “123”; - 将“123”字符串的地址赋值给变量str1。
- 改变str1的指向并没有改变指向的内容
如图:str1 在栈区生成一块内存,abc是直接量直接赋值给str1,abc在方法区申请了一块内存空间,此时是str1指向了abc;123又在方法区中申请了一块内存,现在str1又多了一块123的内存。
此时abc没人用了,此时java虚拟机的垃圾回收机制把abc回收掉。此时还会使用到常量池的概念:
源码总结:byte【】类型的数组,final修饰表示value的值不能改变,value记录的是地址意味着数组不能改变指向,数组一旦定义完毕以后长度就是固定不变了,说明我们这个字符串是一个常量,以后在我们的java程序中只要看见是string类描述的字符串就是常量。长度不能改变,final修饰不能修改不能继承,所以string类修饰的字符串是常量。综合起来所以这个常量是可以被共享的。
2、常量池的概念(原理)
由于String类型描述的字符串内容是常量不可改变,因此Java虚拟机将首次出现的字符串放入常量
池中,若后续代码中出现了相同字符串内容则直接使用池中已有的字符串对象而无需申请内存及创建对
象,从而提高了性能。
首次出现的字符串放入常量池中,再次使用的时候就不需要重新创建对象直接在常量池中拿出来使用就好了。
3、常用的构造方法(熟练、记住)
string类的构造方法演示:
package com.lagou.task12; import javax.crypto.spec.PSource; public class StringConstructorTest { public static void main(String[] args) { // 1.使用无参方式构造对象并打印 String str1 = new String(); // "" 表示空字符串对象,有对象只是里面没有内容 // null 表示空,连对象都没有 System.out.println("st1 = "+str1); //输出空字符串 System.out.println("-------------------------------"); // 2.使用参数指定的byte数组来构造对象并打印 // 'a' = 97 byte[] bArr = {97,98,99,100,101}; // 使用字节数组中的一部分内容来构造对象,表示使用数组bArr中下标从1开始的3个字节构造字符串对象 // 构造字符串的思路:就是先将每个整数翻译成对应得字符,再将所有的字符串起来。 String str2 = new String (bArr,0,3); System.out.println("str2 = "+ str2); // 使用整个字节数组来构造字符串对象 String str3 = new String(bArr); System.out.println("str3 = "+str3); System.out.println("-------------------------------"); // 3.使用字符数组来构造字符串对象 char[] cArr = {'h','e','l','l','o'}; // 使用字符数组中的一部分内容来构造对象 // 思路,直接将字符串起来 String str4 = new String(cArr,2,2); System.out.println("str4 =" + str4); // 使用整个字符数组来构造对象 String str5 = new String(cArr); System.out.println("str5 = "+ str5); System.out.println("-------------------------------"); // 4.使用字符串来构造字符串对象 String str6 = new String("world"); System.out.println("str6 = " + str6); } }
笔试考点:
既然string类可以使用=等方式赋值,又能使用new的方式赋值,那么这两种方式有什么区别?
笔试考点:下面的代码会创建几个对象?分别存放在什么地方?
package com.lagou.task12; public class StringExamTest { public static void main(String[] args) { // 1.请问下面的代码会创建几个对象?分别存放在什么地方? // String str1 = "hello"; // 1个对象 存放在常量池中 // String str1 = new String("hello"); // 2个对象,字面值hello在常量池中,new出来的string对象拿着常量池的hello字符串在堆区中申请了一块内存 // 2.常量池和堆区对象的比较 String str1 = "hello"; // 常量池 String str2 = "hello"; String str3 = new String("hello"); // 堆区 String str4 = new String("hello"); System.out.println(str1 == str2); // 比较地址 true System.out.println(str1.equals(str2)); // 比较内容 true System.out.println(str3 == str4); // false System.out.println(str3.equals(str4)); // true System.out.println(str2 == str4); // false System.out.println(str2.equals(str4)); // true System.out.println("-----------------------------------------------"); // 3. 常量有优化机制,变量没有 String str5 = "abcd"; String str6 = "ab" + "cd"; System.out.println(str5 == str6); // 比较地址 true,因为java中有常量优化机制 String str7 = "ab"; String str8 = str7 + "cd"; System.out.println(str5 == str8); // 比较地址 false +在java语言中就是使用字符串拼接产生新的对象,所以是false } }
4、常用的成员方法(熟练、记住)
案例题目
判断字符串“上海自来水来自海上”是否为回文并打印,所谓回文是指一个字符序列无论从左向右读
还是从右向左读都是相同的句子。
注意:这里的return仅仅用于终端当前程序,实现方法的结束。
package com.lagou.task12; import java.math.BigInteger; public class StringJudgeTest { public static void main(String[] args) { // 1.创建字符串对象并打印 String str1 = new String("1上海自来水来自海上"); // 2.判断该字符串内容是否为回文并打印 for (int i = 0;i<str1.length()/2;i++){ if (str1.charAt(i) != str1.charAt(str1.length()-i-1)){ // 0和8 1和7 2和6 3和5 System.out.println(str1 + ":不是回文!"); return; // 仅仅是用于实现方法的结束 } } System.out.println(str1 + ":是回文!"); } }
注意:
compaerTo方法主要是用来比较调用对象和参数对象的大小关系,大小关系的策略只有三种:大于、小于、等于;结果用布尔类型没法表示,这个时候我们只有使用int类型,正、负、0;主要是调用对象和参数对象比较,compaerToLgnoerCase主要作用是忽略大小写。
在手册中compareTo是这样描述的:按照字典顺序比较两个字符串的大小,比较字符串中的Unicode值,比较两个字符串的长度,返回布尔值,(每个字符都进行比较)
如果第一个字符对比得出结果,后面的就不需要比较了;如果前面的字符相等,就继续往后面比较;如果字符串相等,就比较长度。
package com.lagou.task12; public class StringCompearTest { public static void main(String[] args) { // 1.构造string类型的对象并打印 String str1 = new String("hello"); System.out.println("str1 = "+ str1); // 2.使用构造好的对象与其他字符串对象之间比较大小并打印 // 实际上就是拿着ascii码表做减法运算 System.out.println(str1.compareTo("world")); // 'h' - 'w' 104-119=-15 第一个h和w比就可以区分打消了,后面就不需要比了 System.out.println(str1.compareTo("haha")); // 'e' - 'a' 101 - 97=>4 System.out.println(str1.compareTo("hehe")); System.out.println(str1.compareTo("heihei")); // 'l' - 'i' 108-105=3 System.out.println(str1.compareTo("helloworld")); // 长度比较 5-10=-5 System.out.println(str1.compareToIgnoreCase("HELLO")); // 忽略大小写,相等就是0 } }
案例题目
编程实现字符串之间大小的比较并打印。
案例题目
编程实现上述方法的使用。
package com.lagou.task12; public class StringManyMethodTest { public static void main(String[] args) { // 1.构造String类型的对象并打印 String str1 = new String(" Let Me Give You Some Color To See See!"); //String str1 = new String(" Let Me Give You Some Color To See See!"); System.out.println("str1 ="+ str1); //2.实现各种成员方法的调用和测试 boolean b1 = str1.contains("some"); // 查找字符串中是否包含,该方法区分大小写 System.out.println("b1 = " + b1); // false b1 = str1.contains("Some"); System.out.println("b1 = " + b1); // true System.out.println("--------------------------------------------------"); // 将所有字符串转换为大写 小写 以及去除两边的空白字符 String str2 = str1.toUpperCase(); // 转换为大写 System.out.println("str2 = "+str2); System.out.println("str1 = "+str1); String str3 = str1.toLowerCase(); // 转换为小写 System.out.println("str3 = "+str3); System.out.println("str1 = "+str1); String str4 = str1.trim(); // 去除两边的空格 System.out.println("str4 = "+ str4); System.out.println("---------------------------------------------------"); // 判断字符串是否以。。。开头 以。。。结尾 b1 = str1.startsWith("Let"); System.out.println("b1 = " + b1); // false b1 = str1.startsWith(" "); System.out.println("b1 = " + b1); // ture // 从下标5开始是否以let开头 b1 = str1.startsWith("Let",5); System.out.println("b1 = " + b1); // true b1 = str1.endsWith("See"); System.out.println("b1 = " + b1); // false b1 = str1.endsWith("See!"); System.out.println("b1 = " + b1); // true } }
案例题目
提示用户从键盘输入用户名和密码信息,若输入”admin”和”123456”则提示“登录成功,欢迎使
用”,否则提示“用户名或密码错误,您还有n次机会”,若用户输入三次后依然错误则提示“账户已
冻结,请联系客服人员!”
package com.lagou.task12; import org.w3c.dom.ls.LSOutput; import java.util.Scanner; public class StringEqualsTest { public static void main(String[] args) { Scanner sc = new Scanner(System.in); for (int i = 3;i>0;i--) { // 1.提示用户从键盘输入用户名和密码信息并使用变量记录 System.out.println("请输入你的用户名和密码信息:"); String userName = sc.next(); String password = sc.next(); // 2.判断用户名和密码是否为“admin”和“123456”并给出提示 // if (userName.equals("admin") && password.equals("123456")) { // 用户名忽略大小写 if (userName.equalsIgnoreCase("admin") && password.equals("123456")) { // 把字符串放在前面比较可以防止空指针异常,如果userName或者password是空值就会引发空指针异常` System.out.println("登陆成功,欢迎使用!"); break; } /*else { System.out.println("登陆失败,请输入正确的用户名或密码!"); }*/ if (1 == i){ System.out.println("账户已冻结,请联系客服人员!"); }else{ System.out.println("用户名或密码输入错误,您还有"+(i-1)+"次机会"); } } // 关闭扫描器 sc.close(); } }
案例题目:正向查找
编写通用的代码可以查询字符串"Good Good Study, Day Day Up!"中所有"Day"出现的索引位置并
打印出来。
package com.lagou.task12; public class StringIndexTest { public static void main(String[] args) { // 1.构造String类型的对象并打印 String str1 = new String("Good Good Study, Day Day Up!"); System.out.println("str1 =" + str1); // 2.实现字符串中指定字符和字符串的查找功能 int pos = str1.indexOf('g'); // -1 代表查找失败 System.out.println("pos = " + pos); pos = str1.indexOf('G'); System.out.println("pos = " + pos); // 0 该字符第一次出现的位置 pos = str1.indexOf('G',0); System.out.println("pos = " + pos); // 0 表示从下标0开始查找,包含0 pos = str1.indexOf('G',1); System.out.println("pos = " + pos); // 5 System.out.println("------------------------------------------------------"); // 查找字符串 pos = str1.indexOf("day"); System.out.println("pos = " + pos); // -1 pos = str1.indexOf("Day"); System.out.println("pos = " + pos); // 17 pos = str1.indexOf("Day",17); System.out.println("pos = " + pos); // 17 pos = str1.indexOf("Day",18); System.out.println("pos = " + pos); // 21 System.out.println("------------------------------------------------------"); // 编写通用代码实现将字符串str1中所有Day出现的索引位置找到并打印出来 pos = str1.indexOf("Day"); while(pos != -1){ System.out.println("pos = " + pos); pos = str1.indexOf("Day",pos+1); } System.out.println("------------------------------------------------------"); // 优化一下,把条件放在while循环中,每次循环执行判断,pos+字符串长度可以跳过当前查找的字符串转向下一个查找的字符串,直到返回-1循环结束 pos = 0; while((pos = str1.indexOf("Day",pos)) != -1){ System.out.println("pos = " + pos); pos += "Day".length(); } } }
案例题目
提示用户从键盘输入一个字符串和一个字符,输出该字符(不含)后面的所有子字符串。
笔试考点出现重复代码所以就注销了
package com.lagou.task12; import java.util.Scanner; public class SubStringTest { public static void main(String[] args) { // 1.构造String类型的对象并打印 String str1 = new String("Happy wife, Happy Life!"); System.out.println("str1 = "+ str1); // 2.获取字符串中的一部分内容并打印 // 表示当前字符串中下标12开始获取子字符串 String str2 = str1.substring(12); // 起始位置6,结束位置10 System.out.println("str2 = "+ str2); String str3 = str1.substring(6,10); System.out.println("---------------------------------------------------"); // 3.获取输入字符串中输入字符起的子字符串内容 System.out.println("请输入一个字符串:"); Scanner sc = new Scanner(System.in); String str4 = sc.next(); System.out.println("请输入一个字符:"); String str5 = sc.next(); // 从str4中查找str5第一次出现的索引位置 int pos = str4.indexOf(str5); System.out.println("pos ="+ pos); // 根据该位置获取子字符串 String str6 = str4.substring(pos+1); System.out.println("获取到的子字符串是:" + str6); // 5.笔试考点 // 使用两种方式实现字符串”12345“转换为整数12345并打印 // 方式一:调用integer类中的parseint()方法即可 /* String str7 = new String("12345"); int str8 = Integer.parseInt(str4); System.out.println(str5); // 方式二:利用ascii码来实现类型转换并打印 // ’1‘ - ’0‘ =》 1 以此类推。。。 System.out.println("---------------------------------------------------------"); String str9 = new String("12345"); int ib = 0; for(int i=0;i<str9.length();i++){ ib = ib*10+str9.charAt(i) - '0'; // System.out.println("弟"+i+"次的结果是:" + (ib*10+(str6.charAt(i) - '0'))); } System.out.println("转换出来的结果是:" + ib); // 12345*/ // 如何实现整数到字符串的转换 /* String str9 = "" + ib; // 字符串和任意类型的数据拼接时,拼接的结果都是字符串 System.out.println("str7 = "+ str7);*/ } }
5、正则表达式的概念(了解)
正则表达式本质就是一个“规则字符串”,可以用于对字符串数据的格式进行验证,以及匹配、查
找、替换等操作。该字符串通常使用^运算符作为开头标志,使用$运算符作为结尾标志,当然也可以省
略。
正则表达式使用的例子:
规则14个英文或者7个汉字,使用正则表达式对字符串数据的格式校验
6、正则表达式的规则(了解)
7、正则表达式相关的方法(熟悉)
matchers()方法来源于String类,我们可以看到在英文版中【abc】等上述方法有介绍(中文版中短斤缺两所以查看英文版)。
注意:
1、matches()方法中参数只能传正则表达式的字符串
2、正则表达式只能对数据格式进行验证,无法对数据内容的正确性进行检查,内容的正确性检查需要后台查询数据库
案例题目
使用正则表达式描述一下银行卡密码的规则:要求是由6位数字组成。
使用正则表达式描述一下QQ号码的规则:要求是由非0开头的5~15位数组成。
使用正则表达式描述一下手机号码的规则:要求是由1开头,第二位数是3、4、5、7、8中的一
位,总共11位
描述身份证号码的规则:总共18位,6位数字代表地区,4位数字代表年,2位数字代表月,2位数
字代表日期, 3位数字代表个人,最后一位可能数字也可能是X。