String在设计时被定义成了final类(最终类),所以不能定义String类的子类,String用来表示字符串常量,是引用数据类型,一旦String类对象的字符序列被定义,那么这个字符序列的值是不能再变化的。
创建String类的对象和创建普通类的对象一样,都要经历对象定义与创建两个步骤,主要有以下4种方式来创建String类的对象。
1:通过字符串常量的方式来创建:
该方式是通过英文半角双引号括起来的字符序列(字符串常量)来创建String对象。
例如:
String str1="我爱中国";//字符串常量的方式创建String类对象 String str2="I love Java";//字符串常量的方式创建String类对象
2:通过String类的构造方法来创建
String类提供了多个重要的构造方法:
举例:
String s1="I love Java"; String s2=new String (s1);//创建String对象,值与s1的值相同 String s3=new String();//创建String对象s3,表示空字符(不包括任何字符) char String(StringBuffer sb) String s4=new String(chars);//创建String对象s4,值是字符数组chars中的字符序列
3:通过String类的静态方法value()方法来创建:
该方式主要是通过String类的多个重载的valueOf方法,将基本数据类型和指定对象的数据转换成String类的对象,valueOf()方法的重载方式:
4:通过连接操作符(+)来创建:
当连接操作符(+)两侧的操作数均为字符串对象且都不为null时,将左右两边字符串对象的值拼接在一起形成一个新的字符串对象,如果一侧不是String类的对象,那么会将该对象转换成字符串对象再进行拼接。
举例:
public class Test { public static void main(String[]args){ String s1=String.valueOf(99.5);//将浮点数99.5转换为字符串99.5 String s2="abc"; System.out.println(s1+s2);//将字符串s1和s2进行拼接 } }
输出:
99.5abc
String常用方法:
关于Java中常用的方法有很多,这里我们只展示部分的方法:
import java.util.Locale; public class Test { public static void main(String[]args){ String str="Hello Java"; String str1="Hello Xysf"; String str2="Hello fysf"; char c= str.charAt(2);//检索字符串中的某个字符 System.out.println(c); int i=str.compareTo(str1);//比较两个字符串 System.out.println(i); int x=str.compareToIgnoreCase(str2);//比较两个字符串--不区分大小写 System.out.println(x); char[] arr=str.toCharArray();//将字符串对象转换为字符数组 for(int j=0;j<arr.length;j++){ System.out.print(arr[j]); } System.out.println("\n"); String string=str.concat(str2);//将两个字符串进行拼接 System.out.println(string); boolean s=str.isEmpty();//当字符串长度为0时,返回true System.out.println(s); boolean S=str.startsWith("a");//判断该字符串是否以某字符串为前缀开头 System.out.println(S); boolean a=str.endsWith("va");//判断该字符串是否以某字符串为后缀结束 System.out.println(a); String A=str.toLowerCase();//将字符串中的大写都转变为小写并且返回新串 System.out.println(A); String b=str1.toUpperCase();//将字符串中的小写都转变为大写并且返回新串 System.out.println(b); Boolean B=str1.equals(str);//判断字符串的值是否相等 System.out.println(B); Boolean C=str.equalsIgnoreCase(str1);//判断字符串的值是否相等---忽略大小写 System.out.println(C); } }
输出:
l -14 4 Hello Java Hello JavaHello fysf false false true hello java HELLO XYSF false false
在学习String对象池之前,我们先来学习:
Java对于对象的内存分配:
Java语言把内存分为:栈内存和堆内存,在方法中定义的一些基本类型的变量和对象的引用变量都在方法的栈内存中分配,当在一段代码块中定义一个变量时,Java就在栈内存中为这个变量分配内存空间,当超出变量的作用域后,Java会自动释放掉为该变量分配的内存空间。
堆内存是用来存放由new运算符创建的对象和数组,在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理,在堆中创建了一个对象或数组后,同时在栈中定义一个特殊的变量,让栈中的这个变量的取值等于对象或数组在堆内存中的首地址。
栈内存中进行分配栈中的这个变量就成了对象或数组的引用变量,引用变量实际上保存的是对象或数组在堆内存中的首地址,以后就可以在程序中使用栈的引用变量来访问堆中的对象或者是数组,引用变量就相当于为对象或数组起一个名称,引用变量是普通的变量,定义时在栈内存中进行分配,引用变量在程勋运行到其作用域之外后被释放,而对象或数组本身在堆内存中分配,即使程序运行到使用new运算符创建对象或数组的语句所在代码块之外,对象或数组本身所占据的内存也不会被释放,对象和数组在没有引用变量指向它时会变成垃圾,不能再被使用,但仍然占据内存空间不放,在随后一个不确定的时间被垃圾回收器回收(释放掉),这也是Java比较占内存的原因。
Java中有一个特殊的引用变量null,如果将一个引用变量赋值为null,则表示该引用变量不引用(不指向)任何对象。
除了基本类型之外的类型都是引用类型。
String对象池:
String类型的对象是Java应用中使用率非常高的,我们在程序编写的过程中主要关心的是String对象的值,为了避免频繁的创建与销毁String对象,JVM为了提升性能和减少内存开销,在内存中维护了一段特殊的空间称为字符串对象池。
public class sunday { public static void main(String[]args){ //采用字符串常量的方式创建对象 String str="我爱中国"; String str1="我爱中国"; System.out.println("str和str1指向同一段内存空间?"+(str==str1)); //采用构造方法创建字符串对象 String str2=new String("abcd"); String str3=new String("abcd"); System.out.println("str2和str3指向同一段内存空间?"+(str2==str3)); System.out.println("str和str2内容相同吗?"+(str.equals(str2))); } }
输出:
str和str1指向同一段内存空间?true str2和str3指向同一段内存空间?false str和str2内容相同吗?false
看到这样的输出结果,相信不少小伙伴会产生这样的疑问,在两两内容相同的情况下,为什么str和str1指向的内存空间是同一个,但str2和str3指向的内存空间却不是同一个?
原因是:因为创建方式的不同,str和str1采用字符串常量的方式创建对象,在创建str时,由于字符串对象池还没有字符串常量“我爱中国”,所以会在字符串对象中创建"我爱中国”,然后将它的地址赋给str,当创建str1时,由于“我爱中国”已经在对象池存在,所以不会再创建该内容的字符串对象,而是直接将地址赋值给str1,因此,他两所指向的内存空间相同。
而对于str2和str3采用的是构造方法的方式创建字符串对象
,new关键字会在堆内存开辟空间,str2和str3指向两段不同的堆内存地址。
注意:字符串对象池只对字符串常量的方式创建字符串对象适用。
StringBuffer:
StringBuffer与String相似,他们都可以存储和操作字符串,即包含多个字符的字符串数据,但是String类是字符串常量,是不可更改的常量,而StringBuffer是字符串变量,它的对象是可以扩充和修改的。
StringBuffer只能通过构造方法创建对象。
举例:
StringBuffer str4=new StringBuffer();//建立空的字符串对象 StringBuffer str6=new StringBuffer(4);//建立长度为4的字符串对象 StringBuffer str7=new StringBuffer("Hello");//建立一个初始值为Hello的字符串对象
StringBuffer和StringBuilder的比较:
StringBuffer类和StringBuilder类表示的是字符串变量(可以理解为字符串换缓冲区),也就是说字符串对象被创建后可以改变自身的内容而不用重新创造字符串对象。StringBuffer和StringBuilder这两个类的用法几乎一致,只不过前者是线程安全的,可用在多线程环境中,后者不是线程安全的,常用在单线程环境中。
StringBuffer对象的创建:
StringBuffer类的对象只能通过构造方法的形式来创建,常用的构造方法有以下几种:
StringBuffer的常用方法:
部分使用方法举例:
package Employee; public class sunday { public static void main(String[]args){ StringBuffer str4=new StringBuffer("hello,Java!"); String str="嗨,Java"; System.out.println(str4.append("我是小明"));//字符串追加 System.out.println(str4.insert(4,"_"));//字符插入 System.out.println(str4.reverse());//字符反转 } }
输出:
hello,Java!我是小明 hell_o,Java!我是小明 明小是我!avaJ,o_lleh
注意:
如果对字符串需要进行频繁地修改操作,建议使用StringBuffer或StringBuilder类,若对字符串需要进行频繁地检索操作,建议使用String类。
正则表达式:
正则表达式是一种文本模式,包括普通字符(例如,a到z的字母)和特殊字符(称为“元字符”),正则表达式使用单个字符串来描述,匹配一系列匹配到某个句法规则的字符串,它通常用于判断语句
其常用场合有以下三种:
<1>测试字符串的某个模式,例如,可以对一个输入字符串进行测试,看在字符串是否存在一个电话号码模式或一个信用卡号码模式,这称为数据有效性验证。
<2>替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后可以全部将其删除,或者替换为别的文字。
<3>根据模式匹配从字符串中提取一个子字符串,可以用来在文本或输入字段中查找特定文字。
正则表达式中元字符及其意义:
注意:
在正则表达式中,“.”代表任何一个字符,因此在正则表达式中,如果我们需要普通意义的".“,则我们需要转义字符”".
在正则表达式中,我们也可以使用方括号括起来若干个字符来表示一个元字符,这个元字符可以代表括号中的任意一个字符,例如:regex=“[ab]5”,这样一来,a5,b5都是和正则表达式匹配的字符串。
方括号元字符的常见格式,如下所示:
同样的,在正则表达式中,我们也可以使用限定修饰符来限定元字符出现的个数
限定修饰符的用法如下图所示:
举例:
package Employee; import java.util.Scanner; public class sunday { public static void main(String[] args){ Scanner sc = new Scanner(System.in); System.out.println("请输入手机号码:"); String s1 = sc.nextLine(); String s2 = sc.nextLine(); String regex1 = "1[38]\\D{5,9}";//定义手机号码规则:13/18开头,余下的部分必须为非数字且长度不能小于5,不能大于9 String regex2 = "1[38]\\d{5,9}";//定义手机号码规则:13/18开头,余下的部分必须为数字且长度不能小于5,不能大于9 boolean flag1 = s1.matches(regex1);//判断功能 boolean flag2 = s2.matches(regex2);//判断功能 System.out.println("flag:"+flag1); System.out.println("flag:"+flag2); } }
输出:
请输入手机号码: 13uhnbgdyts 13890765435 flag:true flag:true