目录
API(Application Programming Interface):应用程序编程接口
API(应用程序编程接口):Java写好的程序,我们不需要自己编写,直接调用即可。
案例:键盘录入一个字符串,统计该字符串大写字母字符,小写字母字符,数字字符 出现的次数
API(Application Programming Interface):应用程序编程接口
API(应用程序编程接口):Java写好的程序,我们不需要自己编写,直接调用即可。
1.String类概述
- String类定义的变量可以用于指向字符串对象,然后操作该字符串。
- Java中所有的字符串文字都为此类的对象。
- String类的特点:String被称为不可变字符串类型,它的对象在创建后不能被更改。
- 字符串的内容是不会发生改变的,它的对象在创建后不能被更改。
- 以“”给出的字符串对象,在字符串常量池中存储,且相同内容只会存储1份。
- 只要用双引号引起来的就是字符串,并且用字符串跟任意的数据类型进行相加,那它们做的都是拼接操作,并产生了一个新的字符串。
- 为了方便使用,Java中的lang包是默认导入的,因此在使用其中的类时不需要显式导入该包。这些类包括Object、String、Integer等常用类。这样做可以减少代码量,提高代码的可读性和可维护性。如果您需要使用其他包中的类,则需要显式导入该包。
- java.lang包是Java的核心包 / 是Java默认的包,在使用时候不需要导包。
String是不可变字符串的原因?
- String变量的每次修改都是产生并指向了新的字符串对象。
- 原来的字符串对象都是没有改变的,所以称为不可变字符串。
String为什么要设计成不可变的?
- 便于实现字符串池:开发中会大量的使用字符串String,如果每次声明一个String字符串就创建一个对象,造成极大的空间资源的浪费,因此Java提出了Stringpool的概念,StringPool字符串池就是解决这个问题的,在堆中开辟一块存储空间Stringpool,当初始化一个String变量时,如果该字符串已经存在了,就不会去创建一个新的字符串变量,而是会返回已有该字符串的引用。如果字符串是可变的,某一个字符串变量改变了其值,那么其指向的变量的值也会改变,StringPool将不能够实现。
- 使多线程安全:在并发场景下,多个线程同时读一个资源,是线程安全的,不会引发竞争,但对资源进行写操作时是不安全的,不可变对象不能被写,所以保证了多线程的安全。
- 加快字符串处理速度:因为String字符串对象在创建时会计算并缓存其哈希值,String字符串对象不可变保证了hashcode唯一性,所以在创建对象时其hashCode就可以放心的缓存了,不需要重新计算,如果String对象是可变的,那么每次修改字符串内容都要重新计算哈希值,影响性能,这也是Map喜欢将String作为Key的原因,处理速度要快过其它的键对象,所以HashMap中的额键往往都使用String。
2.String类的常用方法,字符串内容比较
1.如果是字符串比较应该使用什么方式进行比较,为什么?
- 使用String提供的equals方法
- 只关心内容一样就返回true
2. 开发中什么时候用==比较数据
- 基本数据类型比较时使用==
- ==号比基本数据类型比较的是数据值
- ==号比引用数据类型比较的是地址值
import java.util.Scanner;
public class StringAPIEqualsDemo4 {
public static void main(String[] args) {
// 1.正确登录名和密码 变量指向字符串常量池
String sysLoginName = "itheima";
String sysLoginPassword = "123456";
// 2.请您输入登录名称和密码 变量指向堆内存
Scanner sc = new Scanner(System.in);
System.out.println("登录名称:");
String userName = sc.next();
System.out.println("登录密码:");
String userPassword = sc.next();
// 3.判断用户输入的登录名称和密码与正确的内容是否相等
// 等等号==比较的是字符串地址而不是字符串的内容
// 指向字符串常量池 指向堆内存 为false
// if(sysLoginName == userName && sysLoginPassword == userPassword){
if(sysLoginName.equals(userName) && sysLoginPassword.equals(userPassword)){
System.out.println("登录成功!");
}else{
System.out.println("您输入的用户名或密码有误!");
}
// 4.忽略大小写比较内容的API:一般用于比较验证码这样的业务逻辑(验证码不在乎大小写)
String sysCode = "23AdFh";
String code = "23aDfH";
System.out.println(sysCode.equals(code)); // false
System.out.println(sysCode.equalsIgnoreCase(code)); //true
}
}
3.String类常用API-遍历、截取、替换、分割
- 数组的长度length它是一个属性,而字符串的长度length它是一个方法
package com.api.string;
/**
目标:掌握String常用的其他API
*/
public class StringAPiOtherDemo5 {
public static void main(String[] args) {
String name = "我爱你中国love";
// 1.public int length(): 获取字符串的长度
System.out.println(name.length()); // 9
// 2.public char charAt(int index): 获取某个索引位置处的字符
char c = name.charAt(1);
System.out.println(c); //爱
System.out.println("----------------------遍历字符串中的每个字符-----------------------");
for(int i = 0;i < name.length();i++){
char ch = name.charAt(i);
System.out.print(ch); // 我爱你中国love
}
System.out.println();
// 3.public char[] toCharArray(): 把字符串转换成字符数组
char[] chars = name.toCharArray();
for(int i = 0;i < chars.length;i++){
char ch = chars[i];
System.out.print(ch); // 我爱你中国love
}
System.out.println();
// 4.public String substring(int beginIndex,int endIndex): 截取内容,(包前不包后的) substring:截取
String name2 = "Java是最厉害的编程语言!";
// 0123456789
String rs = name2.substring(0,9);
System.out.println(rs); // Java是最厉害的
String rs2 = name2.substring(4,9);
System.out.println(rs2); // 是最厉害的
// 5.public String substring(int beginIndex):从当前索引一直截取到末尾
String rs3 = name2.substring(4);
System.out.println(rs3); // 是最厉害的编程语言!
// 6.public String replace(CharSequence target,CharSequence replacement):作敏感词替换
// CharSequence:理解成字符串,就是String的意思 target:目标,对象 replacement:更换
String name3 = "金三胖是最厉害的80后,金三胖棒棒的!我好爱金三胖";
String rs4 = name3.replace("金三胖","***");
System.out.println(rs4); //***是最厉害的80后,***棒棒的!我好爱***
// 7.public boolean contains(CharSequence s) 看是否包含xxx
System.out.println(name3.contains("金三胖")); // true
System.out.println(name3.contains("金二胖")); // false
// 8.public boolean startsWiths(String prefix) 判断是否以xxx开始
System.out.println(name3.startsWith("金三胖")); // true
System.out.println(name3.startsWith("金三胖是最厉害的")); // true
System.out.println(name3.startsWith("金三胖是最厉害的2")); // false
// 9.public String[] split(String s):按照某个内容把字符串分割成字符串数组返回。
String name4 = "王宝强,贾乃亮,陈羽凡";
String[] str = name4.split(",");
for (int i = 0; i < str.length; i++) {
System.out.println("选择了:"+str[i]);
}
}
}
4.String类开发验证码功能
需求:随机产生一个5位的验证码,每位可能是数字,大写字母,小写字母
分析:
- 定义一个String类型的变量存储a-z,A-Z,0-9之间的全部字符
- 循环5次,随机一个范围内的索引,获取对应字符连接起来即可
import java.util.Random;
/**
练习题:使用String完成随机5位的验证码
*/
public class StringExec6 {
public static void main(String[] args) {
// 1.定义可能出现的字符信息
String datas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
// 2.循环5次,每次生成一个随机的索引,提取对应的字符连接起来即可
String code = "";
Random r = new Random();
for (int i = 0; i < 5; i++) {
// 随机一个索引
int index = r.nextInt(datas.length());
char ch = datas.charAt(index);
code += ch;
}
// 3.输出字符串变量即可
System.out.println(code);
}
}
package com.API20221226;
import java.util.Random;
/**
目标:用String类开发验证码
*/
public class StringTest1 {
public static void main(String[] args) {
String datas = "abcdefghijklmnopqrstovwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
String code = createCode(datas,5);
System.out.println(code);
}
/**
要求用户输入验证码的位数,随机一个验证码出来
*/
public static String createCode(String datas,int n){
Random r = new Random();
String code = "";
for (int i = 1;i <= n;i++) {
// 1.随机一个索引出来
int index = r.nextInt(datas.length());
// 2.获取索引位置处的字符并连接起来
char ch = datas.charAt(index);
code += ch;
}
return code;
}
}
5.模拟用户登录功能
需求:模拟用户登录功能,最多给三次机会
分析:
- 系统后台定义好正确的登录名称和密码
- 使用循环控制三次,让用户输入登录名和密码,判断是否登陆成功
- 登陆成功则不再进行登录,登陆失败给出提示,让用户继续登录
import java.util.Scanner;
/**
练习题:模拟用户登录
*/
public class StringExec7 {
public static void main(String[] args) {
// 1.定义正确的登录名和密码
String okLoginName = "admin";
String okPassword = "it";
// 2.定义一个循环,循环3次,让用户登录
Scanner sc = new Scanner(System.in);
for (int i = 1; i <= 3; i++) {
System.out.println("请您输入登录名称:");
String loginName = sc.next();
System.out.println("请您输入登录密码:");
String password = sc.next();
// 3.判断登录是否成功
if(okLoginName.equals(loginName)){
if(okPassword.equals(password)){
System.out.println("登陆成功!欢迎进入系统随意浏览~~~");
break; // 登陆成功,跳出并结束当前for循环
}else{
// 密码错误了
System.out.println("您的密码不正确,您还剩余" + (3-i) + "次机会登录~~~");
}
}else{
// 登录名错误了
System.out.println("您的登录名称不正确,您还剩余" + (3-i) + "次机会登录~~~");
}
}
}
}
6.手机号码屏蔽
需求:键盘录入一个手机号,将中间4位号码屏蔽。
分析:
- 键盘录入一个字符串
- 调用字符串对象的截取API,截取字符串前三位,后四位
- 将前三位,连接“****”然后继续连接后四位,输出最后结果即可
import java.util.Scanner;
/**
练习题:手机号码屏蔽
*/
public class StringExec8 {
public static void main(String[] args) {
// 1.键盘录入一个手机号码 012 3456 789
System.out.println("请您输入手机号码:");
Scanner sc = new Scanner(System.in);
String tel = sc.next();
// 方案:截取号码的前三位,后四位 012 3456 789
String before = tel.substring(0,3); // 0 1 2
String after = tel.substring(7); // 从索引7开始截取到手机号码的末尾
String s = before + "****" + after;
System.out.println(s);
}
}
案例:键盘录入一个字符串,统计该字符串大写字母字符,小写字母字符,数字字符 出现的次数
package com.string.api;
import java.util.Scanner;
/**
键盘录入一个字符串,统计该字符串大写字母字符,小写字母字符,数字字符出现的次数
*/
public class StringDemo2 {
public static void main(String[] args) {
// 1.键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = sc.next();
// 2.统计 --- 计数器思想
// 定义三个计数器
int bigCount = 0; // 记录大写字母
int smallCount = 0; // 记录小写字母
int numberCount = 0; // 记录数字
for (int i = 0; i < str.length(); i++) {
// i依次表示字符串中的每一个索引
char c = str.charAt(i);
if(c >= 'a' && c <= 'z'){
// char类型变量在参与计算的时候自动类型提升为int 查询ASCII表
smallCount++;
} else if (c >= 'A' && c <= 'z') {
bigCount++;
}else if(c >= '0' && c <= '9'){
numberCount++;
}
}
// 3.输出打印
System.out.println("大写字母有:" + bigCount + "个");
System.out.println("小写字母有:" + smallCount + "个");
System.out.println("数字字符有:" + numberCount + "个");
}
}
案例:拼接字符串
package com.string.api;
public class StringDemo3 {
public static void main(String[] args) {
// 动态初始化数组
int[] arr = {1, 2, 3, 4, 9, 0};
String rs = arrToString(arr);
System.out.println(rs); // [1, 2, 3, 4, 9, 0]
}
// 1.我要干嘛? ---- 遍历数组并把数组拼接成一个字符串
// 2.我干这件事情需要什么才能完成? --- 数组
// 3.我干完了是否需要把结果返回给调用处 --- 返回一个拼接之后的字符串
// 如果调用处需要继续使用,那么必须返回
// 如果调用处不需要继续使用,那么可以返回也可以不返回
public static String arrToString(int[] arr){
if(arr == null){
return "";
}
if(arr.length == 0){
return "[]";
}
// 当代码执行到这里,表示当前数组不为null,长度也不为0
String rs = "";
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
// i--->索引 arr[i]--->元素
// result += arr[i];
System.out.print(i == arr.length - 1 ? arr[i] : arr[i] + ", ");
}
System.out.print(rs + "]");
return rs;
}
}
案例:字符串反转
定义一个方法,实现字符串反转。
键盘录入一个字符串,调用该方法后,在控制台输出结果
例如,键盘录入abc,输出结果cba
package com.string.api;
/**
字符串的反转
*/
public class StringDemo4 {
public static void main(String[] args) {
System.out.println(reverse("7897912315213")); // 312513219798
}
// 1.我要干嘛? --- 字符串的反转
// 2.我干这件事情,需要什么才能完成? --- 需要一个字符串
// 3.调用处是否需要继续使用方法的结果呢? --- 需要结果进行输出
public static String reverse(String str){
// forr:倒着遍历
String rs = "";
for (int i = str.length() - 1; i > 0; i--) {
rs += str.charAt(i);
}
return rs;
}
}
7.String类创建对象的两种方式
- 方式一:直接使用“ ”定义
- 方式二:通过String类的构造器创建对象
package com.api.string;
/**
目标:String类创建字符串对象的两种方式
*/
public class StringDemo2 {
public static void main(String[] args) {
// 方式一:直接使用双引号得到字符串对象
String name = "我爱你中国!";
System.out.println(name); // 根据地址找到这个内容,作了一层特殊优化
// 方式二:通过String类提供的构造器来创建字符串对象
// 1.public String():创建一个空白字符串对象,不含有任何内容(几乎不用)
String s1 = new String(); // s1 = "" ,s1指向了一个空字符串
System.out.println(s1);
// 2.public String(String):根据传入的字符串内容,来创建字符串对象(几乎不用)
String s2 = new String("我是中国人");
System.out.println(s2);
// 3.public String(char[] c):根据字符数组的内容,来创建字符串对象
// 传递一个字符数组,根据字符数组的内容再创建一个新的字符串对象
// 需求:我要修改字符串的内容。 abc ===> Qbc
// abc ===> {'a', 'b', 'c'} ===> {'Q' , 'b' , 'c'} ===> "Qbc"
char[] chars = {'a','b','中','国'};
String s3 = new String(chars); // 内部会自动的把每个字符连在一起,相当于这个构造器会遍历每个字符,遍历完把它拼接成字符串再返回给你
System.out.println(s3); // 把字符数组转成字符串
// 4.public String (byte[] b):根据字节数组的内容,来创建字符串对象
// byte范围:-128-127
// 传递后一个字节数组,根据字节数组的内容再创建一个新的字符串对象
// 应用场景:以后在网络当中传输的数据其实都是字节信息
// 我们一般要把字节信息进行转换,转成字符串,此时就要用到这个构造了。
byte[] bytes = {97, 98, 99, 65, 66, 67};
String s4 = new String(bytes); //它会把字节数组里面的整数全部转成字符串的字符
System.out.println(s4); // abcABC
System.out.println("------------------------------------");
String ss1 = "abc";
String ss2 = "abc"; // true 两个变量指向了同一个字符串对象
System.out.println(ss1 == ss2); // 比较的是两个字符串变量里面存储的地址
char[] chars1 = {'a','b','c'};
String ss3 = new String(chars1);
String ss4 = new String(chars1); // 两个变量指向的是不同的对象
System.out.println(ss3 == ss4); // fasle
}
}
- 栈内存:方法运行的时候进栈,执行完毕出栈
- 堆内存:new出来的对象都在这里
- 方法区:加载字节码文件到方法区单中临时存储
- String Table(串池):就是字符串常量池。JDK7以前,字符串常量池在方法区里面,从JDK7版本开始,字符串常量池从方法区挪到了堆内存。
- 当使用双引号直接赋值时,系统会检查该字符串在串池中是否存在。
- 不存在:创建新的
- 存在:复用
- 以双引号方式给出的字符串对象,在字符串常量池中存储。字符串常量池就在堆内存里面。
- 字符串变量指向字符串对象,字符串变量里面存的是字符串对象的地址,但是变量输出的时候为啥不是地址呢?是根据地址把这个内容给输出的。(与继承有关,因为String类重写了toString方法)。String变量是根据地址找到这个内容。
- 新运算出来的字符串对象是运算出来的,是放在堆内存里面。
- String常被称为不可变字符串类型,它的对象在创建后不能被更改。
- 创建出来的字符串对象没有改变,还是在字符串常量池中。只不过每次字符串变量指向了新的字符串对象。
- String是字符串类,他可以定义字符串变量指向字符串对象。
- String是不可变字符串的原因?
- String变量每次的修改都是产生并指向了新的字符串对象。原来的字符串对象还是在字符串常量池中是没有改变的,所以称String为不可变字符串。
- 以“”方式给出的字符串对象,在字符串常量池中存储,而且相同内容只会在其中存储一份。为了节省内存资源。
区别:
- 以双引号给出的字符串对象,在字符串常量池中存储,且相同内容只会存储1份
- 通过构造器new对象,每new一次就会产生一个新对象,在堆内存中分开存储
8.String类笔试题
public class Test2 {
public static void main(String[] args) {
// 1.下面这行代码总共产生了几个对象?
// 答:这行代码实际上创建了两个对象,双引号的abc要出现在字符串常量池中,而new出来的对象要放在堆内存中
String s2 = new String("abc"); //定义了一个String类型的变量s2指向了new出来的String对象
// 2.下面这行代码没有创建对象,因为常量池中已经有字符串abc,不用再创建了
String s1 = "abc"; //比较的是地址,s1指向了常量池中的abc,而s2指向了new出来的这个对象,所以结果是false
System.out.println(s1 == s2);
}
}
public class Test3 {
public static void main(String[] args) {
String s1 = "abc"; //s1指向的字符串对象是指向常量池中的abc
String s2 = "ab";
// "abc" s3是通过变量s2运算出来的结果,运算出来的结果它不是双引号直接给出来的,它是放在堆内存里面的
// 所以s3会指向堆内存中的abc
String s3 = s2 + "c";
System.out.println(s1 == s3); // fasle
}
}
public class Test4 {
public static void main(String[] args) {
// 1.什么是编译? 把代码翻译成class文件
// Java存在编译优化机制,程序在编译时,"a" + "b" + "c"会直接转成"abc"
// 有什么好处? 极大的节省内存空间,提高效率,提高性能
// 对变量没有进行编译优化机制,只有对字面量才有编译优化机制,
// 因为变量到底最终指向谁只有运行起来才知道
String s1 = "abc";
String s2 = "a" + "b" + "c";
//两个变量都指向了常量池中的abc,所以结果为true
System.out.println(s1 == s2);
}
}
- sc.next( )源码底层它是new出来一个字符串
- 键盘录入得到的字符串是new出来的
package com.string.api;
import java.util.Scanner;
/**
* @author A.G.H
*/
public class StringDemo {
public static void main(String[] args) {
// 1.假设我现在键盘录入一个abc
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str1 = sc.next(); // 键盘录入得到的字符串是new出来的
// 2.代码中再定义一个字符串abc
String str2 = "abc";
// 3.用==号比较,这两者能一样吗?
System.out.println(str1 == str2); // false
}
}