目录
一、Scanner类
1.1Scanner类的概述和方法
要想了解String类,就不得不从Scanner类开始说起,
Scanner类是用来获取用户输入的一个类,是一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。
在对Scanner类进行构造时,我们常常用到的是构造方法是传入一个标准IO流作为参数,
Scanner(InputStream source)
而在java中,System.in就是一个IO流,所以对应的语句是,
Scanner sc = new Scanner(System.in);
然后可以通过sc去访问Scanner类的一些方法来得到键盘输入:
if(sc.hasNextInt()){
int i=sc.nextInt();//获取键盘输入的整数
}
同样的还可以获取Boolean、Byte、Double、Float等等类型的输入。
double d=sc.nextDouble();//获取键盘输入的双精度浮点数
float f=sc.nextFloat();//获取键盘输入的单精度浮点数
byte b=sc.nextByte();//获取键盘输入的字节类型
String s=sc.nextLine();//获取键盘输入的一行字符串
boolean bool=sc.nextBoolean();//获取键盘输入的bool类型
1.2Scanner类获取数据的问题
我们测试这样一段程序,先键盘获取一个整数,然后获取一个字符串,
import java.util.Scanner;
public class StringTest {
public static void main(String []args){
Scanner sc=new Scanner(System.in);
System.out.println("请输入第一个整数:");
int i=sc.nextInt();
System.out.println("请输入第二个字符串:");
String line=sc.nextLine();
System.out.println("i="+i+"line="+line);
}
}
然后我们看结果,
当我们输入了第一个整数10,按下回车键之后没等我们输入第二个字符串,程序已经输出了最后的结果,
那么为什么会这样呢?
nextInt()是键盘录入整数的方法,当我们录入10的时候,这个时候键盘录入的就是“10\r\n”,这个"\r\n"是我们敲击回车键产生的,
但是nextInt()只获取了"10"就结束了,所以"\r\n"被nextLine()获取到了,nextLine()的结束标志就是"\r\n",
所以还没等用户输入一行nextLine()就结束了,所以会输出最终的结果。
nextInt()和nextLine()不能连续使用这个问题我们可以通过再创建一个Scanner对象来解决,
用一个Scanner获取int类型数据,再用另一个Scanner获取字符串数据。
如果不想再创建Scanner对象,那么我们可以两个数据都用nextLine()来获取,然后将获取到的整数字符串转换为整型数据。
二、String类概述
2.1String类的概述
String类是属于java.lang包下的,使用该包下面的类时我们不需要额外导包,可以直接使用,
在官方文档中,String类代表字符串,Java程序中的所有字符串文字(例如"abc")都被实现为此类的实例。
“abc”可以看作是字符串类的一个对象,并且字符串对象是常量,一旦被赋值就不允许改变,
如果我们先给字符串变量str赋值为"123",那么"123"这个字符串对象就无法更改,
如果要改变str存储的字符串,只能重新给一个"456"字符串对象来完成重新赋值的操作,
原来的"123"字符串对象就变成了内存垃圾,所以下面的程序输出为"456",
String str="123";
str="456";
System.out.println(str);
2.2String类的构造方法
String类有以下几种常见的构造方法
public String()//空构造,创建一个空字符串
public String(byte[] bytes)//按照ASCII码表把字节数组转成字符串
public String(byte[] bytes,int index,int length)//把字节数组的一部分转成字符串,index为开始下标,length为解码字节个数
public String(char[] value)//把字符数组转成字符串
public String(char[] value,int index,int count)//把字符数组的一部分转成字符串index为开始下标,length为转换字符个数
public String(String original)//把字符串常量值转成字符串
当使用第二个构造方法时,会使用平台的默认字符集解码byte数组,得到字符串,
这里一般都是ASCII码来解码byte数组,所以byte类型先按照ASCII码表转为char类型,然后拼接char形成字符串。
2.3String类的面试题
2.3.1“==”号和equals方法
前面我们在Object类中已经讨论过了==号和equals方法的区别,
==号可以比较基本数据类型和引用数据类型,当比较基本数据类型时比较的是值,引用数据类型比较的是地址值,
如果用==号比较String的两个对象,那么应该比较的是地址值,而String类重写了equals方法,所以equals比较的是字符串的值,
那么两个相同的字符串,分别用==和equals比较,是不是一个是false一个是true,下面我们看看是不是我们想象中的那样,
String s1="test";
String s2="test";
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
程序输出结果,
我们可以看到程序输出两个都是true,equals比较结果为true我们可以理解,那么为什么==号比较的结果也是true呢?
我们首先分析一下程序如何运行的,首先主方法压入栈后,执行String s1="test"语句,
因为“test”是字符串对象,是常量,初始时会在常量池中找有没有"test"常量,
然后在常量池中的"test"常量的地址值赋给字符串变量s1,接着执行String s2="test"语句,
程序此时又会在常量池中寻找有没有“test”常量,此时找到之前定义过的一个“test”常量,
所以就直接将之前定义的常量地址值赋给字符串变量s2,所以s1和s2实际上指向了同一个地址空间,
这也就是为什么==号比较结果为true的原因。
2.3.2创建对象个数
下面这句话在内存中创建了几个对象?
String s1=new String("abc");
我们分析这句话的执行顺序,首先会在常量池中创建一个“abc”的常量对象,然后调用String的构造方法,
使用new语句则会在堆中也创建一个“abc”对象,然后将堆中的对象地址值赋给s1变量,
我们在这个语句中,使用了String类型作为参数的构造方法,
String(String original)
在java的API文档中,该方法是初始化新创建的String对象,使其表示与参数相同的字符序列,换句话说,新创建的字符串是参数字符串的副本。
那么堆中的“abc”是常量池中的副本,所以本体在内存中一共创建了两个对象,
一个在常量池中,一个在堆中。
2.3.3创建对象的地址值
我们测试一下看看new创建在堆中的“abc”副本的地址和常量池中的"abc"地址是否相同,
String s1=new String("abc");
String s2="abc";
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
输出结果如下,
可以看到第一个比较s1、s2的地址值时结果为false,证明堆中的“abc”地址和常量池中的"abc"地址不相等,
但是String类型重写了equals函数,比较的是字符串是否相同,与地址无关,所以第二个为true。
2.3.4字符串对象相加
如果s1为"a"+"b"+"c",那么在==和equals函数下又会有什么输出结果呢,
String s1="a"+"b"+"c";
String s2="abc";
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
输出结果如下,
我们可以看到两个输出都为true,第二个为true我们可以理解,"a"+"b"+"c"="abc",
但是第一个为什么为true呢?按道理s2在声明的时候常量池中没有字符串“abc“呀,为什么s1与s2的地址相同呢,
原来java中有常量优化机制,在编译时"a"+"b"+"c"就变成了"abc",然后将字符串"abc"赋值给了s1,并且常量池中创建了"abc"字符串,
所以s2在声明的时候会直接使用"abc"的地址值,故s1=s2,
那么如果我们给s1换一种写法,在赋值的时候赋为”ab“,在s2声明之后再加上"c",那么这样会输出什么值呢?
String s1="ab";
String s2="abc";
String s3=s1+"c";
System.out.println(s3==s2);
System.out.println(s3.equals(s2));
输出结果如下,
我们可以看到第一个为false了, java在进行字符串串联操作时,是通过StringBuilder或者StringBuffer类及append方法实现的,
然后利用toString方法转换为字符串对象,首先s1会在常量池中创建"ab"字符串,并把地址赋值给s1,
然后s2在常量池中创建"abc"字符串,并把地址赋值给s2,
创建s3时,涉及到了字符串的串联操作,底层会在堆中创建一个StringBuilder对象,通过append方法串联"ab"和"c",
然后通过toString方法转换为"abc"字符串,此时"abc"字符串是在堆内存的,所以s3记录的是堆内存中的"abc",
所以s3和s2的地址值才会不相同。
三、String类的判断
3.1String类的判断功能
boolean equals(Object obj)//比较字符串的内容是否相同,区分大小写
boolean equalsIgnoreCase(String str)//比较字符串的内容是否相同,忽略大小写
boolean contains(String str)//判断是否包含字符串str
boolean startsWith(String str)//判断字符串是否以指定的字符串str开头
boolean endsWith(String str)//判断字符串是否以指定的字符串str结尾
boolean isEmpty()//判断字符串是否为空
需要注意的是,如果给字符串变量赋值为null,那么不能调用任何方法,否则会出现空指针异常。
tips:null常量可以给任意的引用数据类型赋值。
3.2模拟用户登录练习
Scanner scanner = new Scanner(System.in);//创建键盘录入对象
for(int i=0;i<3;i++) {
System.out.println("请输入用户名:");
String userName = scanner.nextLine();
System.out.println("请输入密码:");
String passWord = scanner.nextLine();
//如果是字符串常量与字符串变量比较,通常是常量调用方法,将变量当作参数传递,防止空指针异常
if ("admin".equals(userName) && "admin".equals(passWord)) {
System.out.println("欢迎" + userName + "登录");
break;
} else {
System.out.println("用户名或密码错误");
System.out.println("您还有"+(2-i)+"次机会");
}
}
四、String类的获取
4.1String类的获取功能
int length()//获取字符串长度
char charAt(int index)//获取指定索引位置的字符
int indexOf(int ch)//返回指定字符在此字符串中第一次出现的索引,这里的ch是字符的ascII码,也可以直接传字符类型的参数,若未找到返回-1
int indexOf(String str)//返回指定字符串在此字符串中第一次出现的索引
int indexOf(int ch,int fromIndex)//返回指定字符在此字符串中从指定位置后第一次出现的索引
int indexOf(String str,int fromIndex)//返回指定字符串在此字符串中从指定位置后第一次出现的索引
String substring(int start)//从指定位置开始截取字符串,默认到末尾
String substring(int start,int end)//从指定位置开始到指定位置结束截取字符串
4.2遍历字符串并统计不同类型字符个数练习
String str = "ABcdef123&*~";
int num_Capital=0;
int num_Lowercase=0;
int num_Digital=0;
int num_other=0;
for (int i = 0;i < str.length();i++){
char c=str.charAt(i);
if(c>='A'&&c<='Z'){
num_Capital++;
}else if(c>='a'&&c<='z'){
num_Lowercase++;
}else if(c>='0'&&c<='9'){
num_Digital++;
}else{
num_other++;
}
}
System.out.println("大写字母个数:"+num_Capital);
System.out.println("小写字母个数:"+num_Lowercase);
System.out.println("数字字母个数:"+num_Digital);
System.out.println("其他字母个数:"+num_other);
五、String类的转换
5.1String类的转换功能
byte[] getBytes()//把字符串转换为字节数组
char[] toCharArray()//把字符串转换为字符数组
static String valueOf(char[] chs)//把字符数组转成字符串
static String valueOf(int i)//把int类型的数据转成字符串
String toLowerCase()//把字符串转成小写
String toUpperCase()//把字符串转成大写
String concat(String str)//把字符串拼接
注意,这里的valueOf方法可以将任意的数据类型转换为字符串,有很多不同的重载参数。
5.2按要求转换字符串
//将给定字符串首字母变为大写,其余均为小写
String str="javA";
String output=str.substring(0,1).toUpperCase().concat(str.substring(1).toLowerCase());
System.out.println(output);
//把数组中的数据按照指定格式拼接为字符串
//例:int[] arr={1,2,3},输出结果为"[1,2,3]"
int[] arr={1,2,3};
String str="[";
for(int i=0;i<arr.length;i++){
if (i==arr.length-1){
str=str+arr[i]+"]";
}else {
str=str+arr[i]+",";
}
}
System.out.println(str);
六、String类的其他功能
6.1String类的替换
String replace(char old,char new)//将字符串中的old字符换为new字符
String replace(String old,String new)//将字符串中的old字符串换为new字符串
如果old字符或者字符串不存在,则保留原字符串不改变。
6.2String类的去除
String trim()//去除字符串两端的空格
6.3String类的按字典顺序比较两字符串
int compareTo(String str)//比较区分大小写
int compareToIgnoreCase(String str)//比较不区分大小写
返回值为int,分别由三种情况负数、零和整数,对应的是比目标字符串小,相等与大三种情况,
比较规则为按照码表值来进行比较。
6.4字符串反转练习
import java.util.Scanner;
public class Overturn {
public static void main(String []args){
//翻转字符串,例"abc"变为"cba"
Scanner sc=new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str=sc.nextLine();
String output="";
char []arr=str.toCharArray();
for(int i=arr.length-1;i>0;i--){
output=output+arr[i];
}
System.out.println("翻转后字符串为:"+output);
}
}
6.5在长字符串中查找短字符串
//统计长字符串中短字符串出现的次数
String longStr="java is not as same as javascript.";
String shortStr="java";
int count=0;
int index=0;
while((index=longStr.indexOf(shortStr)) !=-1){
count++;
longStr=longStr.substring(index+shortStr.length());
}
System.out.println(count);
利用String的indexOf方法找到短字符串在长字符串中出现的下标,计数器自增,
然后将长字符串截取掉,进入下一次循环,最后输出即可。