浅谈API的学习方法
在后续的学习过程中,还会大量使用JDK或者第三方组件、框架提供的API,而在学习这些API时可以利用面向对象的思想去使用它们。
- 了解它的体系结构,即它继承了哪个父类,在Java领域默认都是直接间接继承java.lang.Object,如果父类是一个抽象类,需要抽象类的方法,还有就是实现了哪个接口,接口中的方法都应该被实现类实现。
- 了解它的成员变量,了解底层实现。
- 了解它的构造方法,构造方法用于创建该类的对象,如果它的构造器是私有的,那么它通常是一个工具类,提供的方法都是静态方法,直接通过类名.方法名调用即可。
- 了解它的普通方法,主要是关注方法如何调用,关于方法主要是方法的重载、重写、参数和返回值,声明的异常。
- 多看源码,主要是方法的实现,多调试流程,多仿写,多改写
String类
String类概述
java.lang.String类表示字符串,字符串是日常开发中最常用的数据类型。
因为Java主要是做服务端,也就是后端。当前端发起HTTP请求传给后端的数据格式是字符串,也就是String类。
在Java程序中所有使用一对双引号("")包含的内容(例如“helloworld”)都是String对象的实例。
String类特性
String类是基于字节数组实现的,当操作字符串时底层是一个字节数组,而且该数组是final,也就是必须只能赋一次值,因此说String类是不可变的,每操作一次都会产生一个新的字节数组
/** * String的特点:不可变 */ @Test public void testStringFeatureImmutable(){ String str1="abc"; str1+="d"; //此时内存中有三个字符串对象,分别是abc,d,abcd,字符串的任何操作都会产生一个新的String对象 }
而同一个字符串常量是可以被共享的,即同一个字符串在JVM中只会有一个字符串对象。
/** * 两个相同的字符串在JVM中只会存储一个字符串对象 */ @Test public void testStringFeatureShare(){ String str1="abc"; String str2="abc"; }
创建 String对象的几种方式
在使用String之前,需要借助String类的构造器创建该类的对象。
日常开发中可以通过字符串常量,字节数组和字符数组三种方式来创建String类的对象,也可以直接使用字符串常量赋值给String类型的变量创建一个String类型的对象。
/** * String对象的几种创建方式 */ @Test public void testStringConstruct(){ // 方式1 //直接将字面量的值赋值也是字符串对象 String str="hello"; System.out.println("str = "+str); /*3种构造方式*/ //方式2 //空字符串 String emptyString=new String(""); System.out.println("emptyString = "+emptyString); //方式3 //将字节数组转换为字符串 //打印的是ABCDEF byte[] bytes=new byte[]{65,66,67,68,69,70}; String byteArray=new String(bytes); System.out.println("byteArray = "+byteArray); //打印结果是cde String byteArrayBetweenAnd=new String(bytes,2,3); System.out.println("byteArrayBetweenAnd = "+byteArrayBetweenAnd); //方式4 //将字符数组转换为字符串 char[]chars=new char[]{'a','b','c'}; String charArray=new String(chars); System.out.println("charArray = "+charArray); }
程序运行结果
使用new关键字创建的字符串对象,每次都会在堆内存中开辟内存空间,虽然字符串内容相同,但是地址值不同。
但是当将一个字符串常量赋值给一个字符串变量时,此时的字符串常量存储在常量池当中,相同的字符串常量JVM只会存储一份,也就是同一个String对象。
/** 字符串对象存储的差异 */ @Test public void testStringInstanceDiff() { char[] chars = {'a', 'b', 'c'}; String str1 = new String(chars); String str2 = new String(chars); // ==比较的是内存地址,因为每次new都会在堆内存申请新的空间 因此地址值是不相等 System.out.println("str1 == str2 " + (str1 == str2)); // 此时abc位于常量池中,相同的常量值JVM只会存储一份 String str3="abc"; String str4="abc"; //此时两个引用变量是相等的,因为str3和str4的变量值都位于常量区,它俩都指向同一个常量区地址 System.out.println("str3 == str4 " + (str3 == str4)); }
字符串存储内存结构
程序运行结果
String对象常用方法的使用
- 字符串比较的方法
字符串比较是日常开发中常用的方法,String对象提供了两个方法用于字符串对象的比较:equal()方法和equalsIgnoreCase()方法
- equals()方法用于比较两个字符串对象是否相等,不忽略大小写。
- equalsIgnoreCase()方法用于比较两个字符串对象是否相等,忽略大小写。
在开发中不要使用==判断引用数据类型是否相等,因为默认比较的是引用变量的地址值。
/** * 字符串相等性比较 * == 操作基本数据类型比较的是变量值是否相同 * == 操作引用数据类型比较的是地址值是否相等 * equals()方法用于比较两个字符串相等,不忽略大小写 * equalsIgnoreCase()方法用于比较两个字符串是否相等,忽略大小写 * */ @Test public void testStringEquals(){ int source=10; int target=10; System.out.println("source == target ="+(source==target)); String str1="abc"; char[] chars={'a','b','c'}; String str2=new String(chars); // 因此不能使用==判断两个字符串对象的内容是否相等 System.out.println("str1 == str2 ="+(str1 == str2)); // 比较两个字符串对象的内容相同使用equals()方法,返回一个布尔值,区分大小写 System.out.println("str1.equals(str2) = "+str1.equals(str2)); //例如abc和ABC会返回false String str3="ABC"; System.out.println("str1.equals(str3) = "+(str1.equals(str3))); //某些应用场景会忽略大小写,例如验证码,此时可以使用equalsIgnoreCase()方法 System.out.println("str1.equalsIgnoreCase(str3) = "+(str1.equalsIgnoreCase(str3))); }
程序运行结果
- 获取字符串
- length()方法用于获取字符串的长度,其本质就是除了0以外的字符个数
- concat()方法用于字符串的拼接,等价于+
- charAt(int index) 方法用于查找指定索引的字符,结合for循环可以实现字符串的遍历
- indexOf(String str)查找指定字符串第一次出现的索引位置,还有个重载的方法indexOf(String str,int index),可以实现获取指定第n个次出现的字符串
- lastIndexOf(String str) 反向查找指定的字符串出现的索引位置
- subString(int beginIndex) 按照指定的开始索引截取字符串
- subString(int beginIndex,int endIndex) 按照指定的开始索引和结束索引截取字符串,截取的字符串不包含结束索引的字符串
/** * 获取字字符串 */ @Test public void testStringGet(){ String str="HelloWorld"; //获取字符串的长度 int length =str.length(); System.out.println("HelloWorld字符串的长度是 "+length); //等价于 HelloWorld+你好,世界 String concatStr = str.concat("你好,世界"); System.out.println("拼接后字符串内容是"+concatStr); System.out.println("拼接之前的字符串内容是"+str); //获取2索引位置的元素 char charValue=str.charAt(2); System.out.println("HelloWorld字符串第二个索引的元素是"+charValue); //结合for循环,length()方法和charAt()方法实现字符串的遍历 for (int i = 0; i < str.length(); i++) { System.out.print(str.charAt(i)+","); } System.out.println(); int firstLIndex=str.indexOf("l"); System.out.println("HelloWorld字符串的第一个l字符的索引是"+firstLIndex); //获取HelloWorld字符串的第二个字符串 int secondLIndex=str.indexOf("l",firstLIndex+1); System.out.println("HelloWorld字符串的第二个l字符的索引是"+secondLIndex); //获取HelloWorld字符串倒数第一个字符串l int lastFirstLIndex=str.lastIndexOf("l"); System.out.println("HelloWorld字符串的倒数第一个l字符的索引是"+lastFirstLIndex); //截取HelloWorld的World String hello=str.substring(5); System.out.println("HelloWorld截取Hello的结果是"+hello); //截取HelloWorld的Hello String subString=str.substring(0,5); System.out.println("HelloWorld截取Hello的结果是"+subString); }
程序运行结果
- 字符串的非空判断
字符串非空判断是经常使用到的,在判断之前需要先判断对象是不是null,然后再使用isEmpty()方法判断对象的内容是不是空
/** * 字符串的非空判断 */ @Test public void testStringEmpty(){ //空,没有在堆内存分配内存空间,str1不能使用,如果使用会引发空指针 String str1=null; // 此处会抛空指针 // boolean str1IsEmpty=str1.isEmpty(); //空字符串对象,已经在堆内存分配内存空间,只是空间没有内容,没有内容,即byte[]没有元素 String str2=""; boolean str2IsEmpty=str2.isEmpty(); System.out.println("str2IsEmpty = " +str2IsEmpty); //包含一个空格的字符串 String str3=" "; boolean str3IsEmpty=str3.isEmpty(); System.out.println("str3IsEmpty = " +str3IsEmpty); }
程序运行结果
- 判断字符串是否包含指定的字符串和字符串的替换
/** * contains() 字符串是否包含字串 * replace()字符串替换 */ @Test public void testStringContainsReplace(){ String parent="跟光磊学Java"; boolean isContains=parent.contains("Java"); System.out.println("字符串跟光磊学Java是否包含Java?"+isContains); if(isContains){ //将Java替换成前端 parent=parent.replace("Java","前端"); } System.out.println("将Java替换成前端后 parent = "+parent); }
程序运行结果
5. 字符串大小写转换
/** * 字符串大小写转换 * toLowerCase() 字符串转换为小写 * toLowerCase() 字符串转换为大写 */ @Test public void testStringUpperLower(){ String upper="ABC"; System.out.println("ABC转换为小写的结果是"+upper.toLowerCase()); String lower="abc"; System.out.println("abc转换为大写的结果是"+lower.toUpperCase()); }
程序运行结果
- 字符串和字符数组、字节数组的转换
字符串转换为字节数组时会将字符替换成对应的ASCII值
/** * toCharyArray()字符串转换为字符数组 * 字符串转换为字节数组 */ @Test public void testStringToCharArrayByteArray(){ String str="HelloWorld"; char[] chars = str.toCharArray(); System.out.println("HelloWorld转换为字符数组的结果是" + Arrays.toString(chars)); byte[] bytes = str.getBytes(); System.out.println("HelloWorld转换为字节数组的结果是" + Arrays.toString(bytes)); }
程序运行结果
- 字符串删除首尾空格
/** * trim()字符串去掉首位空格 * */ @Test public void testStringTrim() { String str=" Hello World "; System.out.println("去掉空格前是"+str); System.out.println("掉空格后的结果是"+str.trim()); }
程序运行结果
- 字符串按照指定的规则拆分
/** * split(String regex)按照指定的规则拆分字符串 */ @Test public void testStringSplit(){ String language="C,Java,JavaScript,Go,Python,C++"; //按照逗号拆分字符串 String[]languages=language.split(","); System.out.println("必须掌握的编程语言:"+Arrays.toString(languages)); }
程序运行结果
字符串常见应用
- 使用字符串实现模拟用户登录
package net.ittimeline.java.core.jdk.api.lang;import java.util.Scanner;/** * 字符串应用:模拟用户登录 * * @author tony 18601767221@163.com * @version 2020/12/17 17:45 * @since JDK11 */public class StringLoginTest { public static void main(String[] args) { int count = 0; String targetUserName = "tony"; String targetPassword = "123456"; int maxLoginCount=3; Scanner input = new Scanner(System.in); while (count < 3) { System.out.println("请输入你的用户名"); String userName = input.nextLine(); System.out.println("请输入你的密码"); String password = input.nextLine(); if (targetUserName.equals(userName) && targetPassword.equals(password)) { System.out.println("登录京东成功"); break; }else{ System.out.println("用户名或者密码错误,登录失败"); } count++; System.out.printf("你还剩下%d次机会",maxLoginCount-count); } input.close(); }}
程序运行结果
- 字符串遍历
package net.ittimeline.java.core.jdk.api.lang;import java.util.Scanner;/** * 字符串应用:遍历字符串 * * @author tony 18601767221@163.com * @version 2020/12/17 18:02 * @since JDK11 */public class StringTraversalTest { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("请输入你的名字"); String userName=input.nextLine(); for (int i = 0; i
程序运行结果
- 统计字符串
package net.ittimeline.java.core.jdk.api.lang;import java.util.Scanner;/** * 字符串应用:字符串统计,读取用户输入的字符串,判断输入的大写字母、小字母以及数字的个数 * * @author tony 18601767221@163.com * @version 2020/12/17 18:06 * @since JDK11 */public class StringStatisticTest { public static void main(String[] args) { int lowerCaseCount=0; int upperCaseCount=0; int numberCount=0; System.out.println("请输入一段字符串"); Scanner input=new Scanner(System.in); String str=input.nextLine(); for (int i = 0; i < str.length(); i++){ char ch=str.charAt(i); if(ch>=97 && ch <=97+26){ lowerCaseCount++; }else if(ch>=65&&ch<=65+26){ upperCaseCount++; }else if(ch>=48&&ch<=48+9){ numberCount++; } } System.out.printf("你输入的字符串是%s,其中大写字母的个数是%d,小写字母的个数是%d,数字的个数是%d",str,upperCaseCount,lowerCaseCount,numberCount); }}
程序运行结果
- 实现Arrays.toString()方法
/** 实现Arrays.toString(int[]a)方法 */ @Test public void testStringConcat() { int[] numbers = {1, 2, 4, 5, 7, 8, 9, 6, 3}; //初始化拼接字符串 String str = new String("["); //遍历数字 for (int i = 0; i < numbers.length; i++) { if (i < numbers.length - 1) { //不是最后数字就拼接数字和逗号 str = str.concat(numbers[i] + ","); } else if (i < numbers.length) { //是最后数字就拼接数字和] str = str.concat(numbers[i] + "]"); } } System.out.println(str); }
程序运行结果
- 字符串反转
/** 字符串反转 */ @Test public void testStringInversion() { String str = "跟光磊学Java开发"; System.out.println("跟光磊学Java开发反转之前 str = " + str); String result = new String(); for (int i = str.length()-1; i >= 0; i--) { result+=str.charAt(i); // } System.out.println("跟光磊学Java开发反转之后 result = " + result); }
字符串反转
StringBuilder类
StringBuilder类概述
由于String的不可变特性,每次操作都会产生一个新的String对象,这样耗时号内存。因此SUN公司又设计了StringBuilder类
java.lang.StringBuilder表示 一个可变的字符串类,这里的可变表示StringBuilder对象中的内容是可变的。
通过其父类java.lang.AbstractStringBuilder的源码可以看出它的底层实现采用一个不是final修饰的字节数组。
StringBuilder类的构造方法
在使用StringBuilder对象提供的方法之前,同样需要创建StringBuilder的对象。
我们可以使用两种方法来创建StringBuilder对象:空字符串创建StringBuilder对象和非空字符串创建StringBuilder()对象
/** StringBuilder常用构造器 */ @Test public void testStringBuilderConstruct() { // 使用空字符串创建一个StringBuilder对象 StringBuilder emptyString = new StringBuilder(); System.out.println("emptyString.length() = " + emptyString.length()); // 使用字符串创建一个StringBuilder对象 String str = "跟光磊学Java编程"; StringBuilder content = new StringBuilder(str); System.out.println("content.length() = " + content.length()); }
程序运行结果
如果使用空字符串创建StringBuilder对象,通过源码得知,默认会开辟长度为16个字节的长度
/** * Constructs a string builder with no characters in it and an * initial capacity of 16 characters. */ @HotSpotIntrinsicCandidate public StringBuilder() { super(16); } /** * Creates an AbstractStringBuilder of the specified capacity. */ AbstractStringBuilder(int capacity) { if (COMPACT_STRINGS) { value = new byte[capacity]; coder = LATIN1; } else { value = StringUTF16.newBytesFor(capacity); coder = UTF16; } }
StringBuilder常用方法
在创建StringBuilder对象后就可以调用StringBuilder对象的方法。
- 使用StringBuilder实现字符串拼接
/** * append():拼接任意类型的数据返回本身 */ @Test public void testStringBuilderAppend(){ StringBuilder emptyString=new StringBuilder(); emptyString.append(2020); emptyString.append("年"); StringBuilder result=emptyString.append("跟光磊学Java开发"); System.out.println(result); System.out.println("result==emptyString = "+(result==emptyString)); }
程序运行结果
无论拼接多少次返回的都是同一个StringBuilder对象
- 在指定的位置插入字符串
/** * insert():在指定的位置插入数据并返回本身 */ @Test public void testStringBuilderInsert(){ StringBuilder emptyString=new StringBuilder(); emptyString.append("跟光磊学Java开发,"); emptyString.append("跟光磊学Linux运维"); emptyString.insert(11,"跟光磊学前端开发,"); System.out.println(emptyString); }
程序运行结果
- 字符串反转
/** * reverse():反转字符串并返回 */ @Test public void testStringBuilderReverse(){ StringBuilder helloWorld=new StringBuilder("界世好你"); StringBuilder reverseResult = helloWorld.reverse(); System.out.println("reverseResult==helloWorld = "+(reverseResult==helloWorld)); System.out.println(helloWorld); }
程序运行结果
- StringBuilder和String对象的相互转换
/** * StringBuilder和String的相互转换 */ @Test public void testStringBuilderToString(){ String str="HelloWorld"; //String转StringBuilder StringBuilder content=new StringBuilder(str); //StringBuilder转String str=content.toString(); }
- 使用StringBuilder实现Arrays.toString()方法
/** * 使用StringBuilder实现Arrays.toString()方法 */ @Test public void testStringBuilderAppendArray(){ int[] numbers=new int[]{1,2,4,5,7,8,9,6,3}; StringBuilder content = new StringBuilder("["); for (int i = 0; i < numbers.length ; i++) { if(i
程序运行结果
- 使用链式编程实现字符串反转
/** * 使用StringBuilder实现字符串反转 */ @Test public void testStringBuilderReverseString(){ String str="发开avaJ学磊光跟"; String reverseStr=reverse(str); System.out.println(reverseStr); } /** * 定义一个字符串反转的方法返回元字符串 * @param str * @return */ public String reverse(String str){ // 链式编程 return new StringBuilder(str).reverse().toString(); }
程序运行结果