思考题1
String str=new String("abc"); 这行代码创建了几个String对象?
答:1个或2个。
(1)首先在堆中(不是常量池)开辟一个内存空间,并让str引用指向该空间
(2)在字符串常量池中查看,是否存在内容为"abc"字符串对象
(3)若存在,则将new出来的字符串对象与字符串常量池中的对象联系起来(1个)
(4)若不存在,则在字符串常量池中创建一个内容为"abc"的字符串对象,并将堆中的对象与之联系起来(2个)
思考题2
String str="abc"; 我们知道这行代码创建了一个String对象。
那这里呢?String a="abc"; String b="abc";
答:还是一个。
再看看这里呢?String a="ab"+"cd";
通过编译器优化后,得到的结果是String a="abcd"
答:零个或一个。如果字符串常量池中存在abcd,则该语句并不会创建对象,只是将字符串常量池中的引用返回而已;如果字符串常量池中不存在abcd,则会创建并放入字符串常量池,并返回引用。
如果用String s=new String("abcd"),不管常量池里有没有"abcd",它都会在堆中重新分配一块内存,定义一个新的对象。因此提倡大家用引号包含文本的方式来创建String对象以提高效率,这也是我们在编程中常采用的。
思考题3
String s="hello"+"world";//编译器优化后,直接将helloworld对象放入字符串池中。
System.out.println(s=="helloworld");//结果是true;
String str1="hello";
String str2="world";
String s = str1+str2;
System.out.println(s=="helloworld");//结果是啥?
答案是false。
JVM对形如String str="hello"+"world";根据编译器合并已知量的优化功能,在池中开辟一块空间,存放合并后的String常量"helloworld",但是它是在编译时刻那么做的;而String s = str1+str2; 是在运行时刻才能知道,也就是说str1+str2是在堆里创建的, s引用当然不可能指向字符串常量池里的对象,s引用指向堆内存。
String s=str1+"world";//不放在字符串池中,而是在堆中分配。
System.out.println(s=="helloworld");//结果是啥?
答案是false。
总之,创建字符串常用的两种方式:
1.""创建的字符串在字符串常量池中。
2.new 创建字符串时,首先查看池中是否有相同的字符串,如果有则拷贝一份放到堆中,然后返回堆中的地址;如果池中没有则在堆中创建一份,然后返回堆中的地址,
3.在对字符串赋值时,如果右操作数含有一个或一个以上的字符串引用时,则在堆中再建立一个字符串对象,返回堆中的引用。 如:String s= str1+"world";
思考题4
String s = new String(“abcd”);和String s = “abcd”;的区别是什么?
答:
String s="abcd"是一种非常特殊的形式,和new 有本质的区别。它是java中唯一不需要new 就可以产生对象的途径。以String s="abcd";形式赋值在java中叫直接量,它是在常量池中而不是象new一样放在压缩堆中。这种形式的字符串,在JVM内部发生字符串拘留,即当声明这样的一个字符串后,JVM会在常量池中先查找有有没有一个值为"abcd"的对象,如果有,就会把它赋给当前引用.即原来那个引用和现在这个引用指点向了同一对象,如果没有,则在常量池中新创建一个"abcd",下一次如果有String s1 = "abcd";又会将s1指向"abcd"这个对象,即以这形式声明的字符串,只要值相等,任何多个引用都指向同一对象。而String s = new String("abcd");和其它任何对象一样.每调用一次就产生一个对象,只要它们调用。
字面量创建字符串会先在字符串池中找,看是否有相等的对象,没有的话就在堆中创建,把地址驻留在字符串池;有的话则直接用池中的引用,避免重复创建对象。
new关键字创建时,前面的操作和字面量创建一样,只不过最后在运行时会创建一个新对象,变量所引用的都是这个新对象的地址。
String类的转换功能
public byte[] getBytes():把字符串转换为字节数组。
public char[] toCharArray():把字符串转换为字符数组。
public static String valueOf(char[] chs):把字符数组转成字符串。
public static String valueOf(int i):把int类型的数据转成字符串。
valueOf方法还有long、float、double、Object等等类型。
public String toLowerCase():把字符串转成小写。
public String toUpperCase():把字符串转成大写。
String类的其他功能
1.String的替换功能
public String replace(char old,char new) 将指定字符进行互换
public String replace(String old,String new)将指定字符串进行互换
2.String的去除字符串两端空格
public String trim()去除两端空格
3.String的按字典顺序比较两个字符串
public int compareTo(String str)会对照ASCII 码表 从第一个字母开始进行减法运算 返回的就是这个减法的结果(调用者减去传入者)
如果字符串相等返回值为0,不等返回其他数值。
比较方法是先比较对应字符的大小(ascii码值),从第一个字母开始比较。
如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的差值(ascii码值)(负值:前字符串的值小于后字符串;正值:前字符串大于后字符串)
如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较。以此类推,直至比较的字符或被比较的字符有一方全比较完,这时就比较字符串的长度。
public int compareToIgnoreCase(String str)跟上面一样 只是忽略大小写的比较
public boolean matches(String regex)
判断此字符串是否匹配给定的正则表达式
一、正则表达式
(一)概述
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
import java.util.Scanner;
public class MyTest {
public static void main(String[] args) {
String regex="[1-9][0-9]{4,14}";//QQ号码的正则表达式
Scanner sc = new Scanner(System.in);
System.out.println("注册——请输入符合规则的QQ号码:");
String s = sc.nextLine();
boolean matches = s.matches(regex);//判断此字符串是否匹配给定的正则表达式
if(matches){
System.out.println("输入的QQ号码符合规则");
}else{
System.out.println("输入的QQ号码不符合规则");
}
}
}
(二)正则表达式的组成规则
以下规则字符在java.util.regex.Pattern类中
1.字符
x 即字符 x。举例:‘a’表示字符a
\\ 反斜线字符。
\n 新行(换行)符 (’\u000A’)
\r 回车符 (’\u000D’)
2.字符类
[abc] a、b 或 c(简单类)
[^abc] 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a到 z 或 A到 Z,两头的字母也包括在内
[0-9] 0到9的字符都包括
3.预定义字符类
. 即任何字符。
那么.字符本身,怎么表示呢? \.
\d 数字:[0-9]
\w 单词字符:[a-zA-Z_0-9]包括下划线
4.边界匹配器
^ 行的开头
$ 行的结尾
\b 单词边界
就是不是单词字符的地方。
举例:hello world?haha;xixi (空格问号分号都是单词边界)
5.Greedy 数量词
X? X出现一次或一次也没有 比如""空串 就是没有
X* X出现零次或多次 (大于等于1次 都算多次)
X+ X出现一次或多次
X{n} X出现恰好 n 次
X{n,} X出现至少 n 次
X{n,m} X出现至少 n 次,但是不超过 m 次
案例演示
public class MyTest1 {
public static void main(String[] args) {
String regex = "a";
regex = "[abcdef]"; //允许出现列表中的某一个字符
regex = "[a-z]";//允许出现26个小写字母的任意一个
regex = "[A-Za-z]";//允许出现大小写字母任意一个
regex = "[0-9]";//允许出现0-9任意一个
regex = "[a-zA-Z0-9]";//允许出现大小写字母或0-9任意一个
regex = "[^0-9]"; //^不允许出现列表中的任意一个
regex = ".";//通配单个任意字符
regex = "\\.";// \\转义字符 \\.这个意思就是匹配点.本身
regex = "\\|"; //由于|本身代表或的意思,因此需要转义
regex = "\\d";//跟[0-9]意思一样
regex = "\\w";//跟[a-zA-Z_0-9]意思一样
regex = "[a-z]+"; // +可以出现一个或多个
regex = "a?"; //一次或一次也没有 比如 "" 空串 就是没有
regex = "[a-z]*";//零次或多次 (大于等于1次 都算多次)
regex = "[a-z]{6}";//a-z正好6个
regex = "[0-9]{6,}";//0-9的数至少6个
regex = "[0-9]{6,16}";//0-9的数大于等于6个小于等于16个
boolean flag = "123499988766454343".matches(regex);
System.out.println(flag);//false
}
}
(三)正则表达式的判断功能
public boolean matches(String regex)
判断此字符串是否匹配给定的正则表达式
(四)正则表达式的分割功能
String类的功能:public String[] split(String regex)
根据给定正则表达式的匹配拆分此字符串。
案例演示1
有一个由个人信息组成的字符串,需要提取其中的有效信息。
public class MyTest {
public static void main(String[] args) {
String s="张三==23==男";
String regex="==";
String[] a = s.split(regex);
System.out.println(a[0]);
System.out.println(a[1]);
System.out.println(a[2]);
}
}
五)正则表达式的替换功能
String类的功能:public String replaceAll(String regex,String replacement)
将和正则表达式匹配的字符串替换为给定的字符串
public class MyTest {
public static void main(String[] args) {
String s1="I love you";
String s2 = s1.replace("you", "her");//replace方法
System.out.println(s2);
//需要将s3的所有数字替换为空格,这时replace方法无法做到
String s3="I21154love54547478you";
String regex="[0-9]+";
String s4 = s3.replaceAll(regex, " ");//replaceAll方法
System.out.println(s4);
}
}