字符串

什么是JDK API

JDK中包含大量的API类库,所谓API(Application Programming Interface,应用程序接口)就是一些已经写好的、可供直接调用的功能(在java语言中,这些功能以类的形式封装)

例如:字符串操作、集合操作、文件操作、输入输出操作、网络操作、多线程等等。

String字符串:极其重要的API类,一切文字的显示都用到它

1、java中最重要的基础API

2、java.lang.String使用了final修饰,不能修改

3、字符串底层封装了字符数组(数据类型一样)及针对字符串数组的操作算法

4、字符串一旦创建,对象永远无法改变,但字符引用可以重新赋值

5、Java字符串在内存中采用Unicode编码方式,任何一个字符对应两个字节的定长编码

Unicode就是为每一个对象和符号分一个数,因为计算机只能处理数字

6、字符串的长度:是字符的个数

字符串内存的占用:字节数,每个字符2个字节

“Tom你好”:字符串长度为5,在内存中占用10个字节

String常量池:

1、Java为了提高性能,静态字符串(字面量/常量/常量连接的结果)在常量池中创建,并尽量使用同一个对象,重用静态字符串;

2、对于重复出现的字符串直接量,JVM会首先在常量池中查找,如果存在即返回该对象


//测试静态字符串缓冲池现象,减少创建对象,优化性能
	//静态字符串包括:字面量(直接量)、“字面量”的运算结果、常量
	//                "杯子1"            "杯子"+1
	//@Test
	public void testString1() {
		String tom="杯子1";
		String jerry="杯子1";
		String andy="杯子"+1;//编译以后是”杯子1“,运行期间,与tom引用同一个对象,这是字面量的运行结果
		System.out.println(andy);
		
		int n=1;
		String john="杯子"+n;
		//计算变量,编译以后没有值,运行之后n为1,运行期间连接并且创建新字符串,不在静态池中分配
		System.out.println(john);
		
		System.out.println(tom==andy);//true
		System.out.println(tom==jerry);//true
		System.out.println(tom==john);//false
	}
public class StringConstantPool {

	public static void main(String[] args) {
		String str1="Hello";
		String str2="Hello";//不会创建新的String对象,而是使用常量池中已有的"Hello"
		System.out.println(str1==str2);//"=="比较的是常量的值,是str1的地址和str2的地址
		String str3=new String("Hello");//使用new关键字创建新的对象
		System.out.println(str1==str3);
	}

}

使用indexOf实现检索:

indexOf方法用于实现在一个字符串中查找另一个字符串

String提供了几个重载的indexOf方法

int indexOf(String str):在字符串中检索str,返回第一次出现的位置,若没找到则返回负数

int indexOf(String str,int fromIndex):从字符串的fromIndex位置开始检索

int lastIndex(String str,int from):str在字符串中多次出现时,将返回最后一个出现的位置

public void testIndexOf() {
		String url="http://www.nhgjfh.com.cn/index.html";
		         // 01234567890123456789012345678901234
		int index=url.indexOf("/");
		System.out.println(index);//5
		
		index=url.indexOf("/", 7);//从第7个位置开始查找
		System.out.println(index);//24
		
		index=url.lastIndexOf("/");//从后往前找
		System.out.println(index);//24
		
		String host="nhgjfh.com.cn";
		if(url.indexOf(host)>=0) {
			System.out.println(url.indexOf(host));//"nhgjfh.com.cn"在字符串中11的位置
			System.out.println("访问nhgjfh的URL");
		}
	}

使用substring获取字符串:

1、substring方法用于返回一个字符串的子字符串

2、substring常用重载方法定义如下:

A、String substring(intbeginIndex,int endIndex):返回字符串从beginIndex开始(包括)到endIndex(不包括)结束的字符串,包含开始,不包含结束

B、String substring(intbeginIndex):返回字符串中从下标beginIndex(包括)开始到字符串结尾的子字符串,从开始的位置到最后全要

public void testSubstring() {
		//使用API可以简化编程,不用API使用for循环也可以处理同样的问题。
		String email="tengxun@qq.com" ;
		           // 01234567890123
		int index=email.indexOf('@');
		String name=email.substring(0,index);//包括0,不包括7,tengxun
		System.out.println(index+1);//qq.com
		
		String host=email.substring(8);
		System.out.println(host);
	}

trim()去掉空字符:

空字符:编码小于空格的字符,空格也是字符!不仅仅是空格!

包括:空格 tab \n \r

关于String API:如果返回值与原字符不同,就返回新字符串对象,原字符串对象不变;如果与原字符串对象相同,经常返回原字符串对象本身。

public void testTrim() {//把空字符都去掉
		String name=" \n\t\r Tom\n \t\r";
		name=name.trim();
		System.out.println(name);
	}
public void testTrim2() {
		String name="   Tom   ";
		
		name.trim();
		System.out.println(name);//   Tom   引用name没有被改变,原对象不变
		
		name=name.trim();//name引用被改变了
		System.out.println(name);
	}
public void testTrim3() {
		String name="Tom";
		String n=name.trim();
		System.out.println(name==n);//true
	}

charAt:遍历字符串

charcharAt(int index):用于返回字符串指定位置的字符

经常用来进行遍历字符串

当使用String API不能达到业务目的,可以采用charAt迭代(遍历)处理每个字符,可以实现复杂的字符处理。

测试用例:

将字符串中每个空格后(每个单词的首字母)的小写字母转换成大写字母:

public void testcharTest() {
		String str="What is Java";
		char ch=str.charAt(0);//W
		System.out.println(ch);
		
		String name="我爱大笨蛋";		          
		//打印字符串中每个字符的编码,遍历每个字符
		for(int i=0;i<name.length();i++) {
			char c=name.charAt(i);
			System.out.println((int)c);//强制类型转换,将字符都变成数了
		}
		
	}
public void testcharTest2() {
		//将字符串中每个空格后的字母转换为大写字母
		//当遇到前一个字符是空格,后一个字符是小写字母时候,需要转换,而且转换结果是新的
		//设计pre 代表前一个字符,ch 代表当前的字符
		String str="what is java!";
		char pre=' ';
		char[] chs=new char[str.length()];//输出的字符缓冲区,因为原数组不能被改变
		for(int i=0;i<str.length();i++) {
			char ch=str.charAt(i);
			//System.out.println(pre+","+ch);//pre和ch是每两个相邻的字符,输出紧挨着的两个字符
			if(pre==' '&&(ch>='a'&&ch<='z')) {//如果前一个是空格,后一个是小写字母的时候
				System.out.println(pre+","+ch);	
				ch=(char)(ch+('A'-'a'));//将小写字母转换成大写字母
			}
			chs[i]=ch;//将每个字符复制到数组中
			pre=ch;
		}
		String s=new String(chs);//字符数组转成字符串
		System.out.println(s);
	}

startsWith和endsWith

检查一个字符串是否以指定字符串开头或结尾

public void testEndWith() {
		String file="tetris.png";
		if(file.endsWith(".png")) {//以.png结尾
			System.out.println("这是一个png图片文件");
		}
		//startsWith()的用途:检查命令
		String cmd="get day01.zip";
		if(cmd.startsWith("get")){//下载文件命令只看开头是get就行
			System.out.println("这是下载文件命令");
		}
	}

大小写变换:

转换字符串中英文字母的大小写形式

public void testToLowerCase() {
		String file="tetris.PNG";
//		file=file.toLowerCase();
//		if(file.endsWith("png")) {
//			System.out.println("这是一个图片文件");
//		}
		if(file.toLowerCase().endsWith("png")) {
			System.out.println("这是一个图片文件");
		}
	}

valueOf

将其他类型转换为字符串类型

String.valueOf()可以将任何类型转换为String用于最终的输出(在界面上显示结果)

public void testValueOf() {
		int i=65;
		//i=00000000 00000000 00000000 01000001
		//计算机内部没有十进制,只有二进制,需要利用算法将二进制的数转换为字符串“65”,最终输出十进制的“65”
		System.out.println(i);
		String s=String.valueOf(i);//将其他类型转换为字符串类型
		//valueOf的底层调用了Integer.toString(i)
		System.out.println(s);
		
		char[] chs= {'A','B','C'};
		s=String.valueOf(chs);
		System.out.println(s);
	}

字符串API的特点:

1、是final类型

2、String对象是不可改变的(叫做不变模式)

3、String API如果改变了内容,就返回新对象,原对象永远不变

4、String API方法是对char数组的操作算法

注意:没有API,或者不用API可以利用for循环处理字符数组实现相应的功能,如果优化的好的话,性能优于String API。

public class StringDemo {

	public static void main(String[] args) {
		String name="Tom";//name是对象的引用,Tom是对象
		String other=name;//other和name引用了同一个对象Tom
		name=name+" and Jerry";//java的动态字符串连接运算产生了新的字符串对象:"Tom and Jerry"
		//name被赋值引用了新字符串对象,原字符串对象不变,字符串引用变量name被改变了!
		System.out.println(name);
		System.out.println(other);//输出结果是:"Tom",说明对象没变
	}

}


StringBuilder

StringBuilderappend(String str);追加字符

StringBuilderinsert(int dstOffset,String s);插入字符串

StringBuilderdelete(int start,int end);删除字符串

StringBuilderreplace(int start,int end,String str);替换字符串

StringBuilderreverse();字符串反转

StringBuilder的很多方法的返回值均为StringBuilder类型,这些方法的返回语句均为:return this,返回的均为本身。一直在修改StringBuilder中的内容。这是跟String的不同。

public void testStringBuilder() {
		StringBuilder buf=new StringBuilder();
		//buf中的内容一直在被操作修改
		buf.append("马伊利说:");//返回buf本身
		buf.append("且行且珍惜");
		buf.insert(3, "对文章");
		buf.replace(1, 3, "司令");
		
//		buf.append("马伊利说:")//可以在本身上面进行操作,因为返回值就是buf本身,方便镰蟹
//		   .append("且行且珍惜")
//		   .insert(3, "对文章")
//		   .replace(1, 3, "司令");
//		
		String str=buf.toString();
		System.out.println(str);
	}

StringBuilder总结:

StringBuilder是可变字符串,字符串的内容计算,建议采用StringBuilder实现,这样性能会好一些。Java的字符串String连接的过程是利用StringBuilder实现的。

如:

Strings=“杯子”;

Stringss=s+1;

//ss=newStringBuilder(s).append(1).toString();

Stringss=s+1+”3”;

//ss=newStringBuilder(s).append(1) .append(“3”).toString();

很多的连接要用ss=new StringBuilder(s).append(1).toString();这种形式

单个的或两个的可以使用累加+

StringBuilder和String

StringBuilder:内部的字符数组内容和长度可变,是可变字符串

String:内部字符数组是不可变的,是不变字符串

那么java为什么要弄两个:

StringBuilder的字符操作性能好于String,StringBuilder不需要复制,而String改变的就是复制后的内容,原对象不变

StringBuffer和StringBuilder方法都一样,区别是:

StringBuffer:是线程安全的,同步处理的,性能稍慢

StringBuilder :是非线程安全的,并发处理的,性能稍快

API现成的类(程序):

1、java API是java(oracle)提供的

系统标准API:System  String  Scanner Integer  Math

2、第3方API

如:Junit.jar  Spring MyBatis  Apache提供的

3、可以自己开发一些API

如:开发方法:将空格前每个字母大写

4、一般情况下,任何技术都有现成的API;跟业务有关的都需要自己写。

Java系统API

任何程序(API)=数据+算法

1、String类=字符数组(数据)+操作算法(方法)

     一旦创建对象,数据不可改变

2、StringBuilder=字符数组(数据)+操作算法(方法)

     可以利用方法改变字符数组的数据,最后需要toString

3、字符数组(数据)也是字符串,但是没有算法

     字符数组(数据)+优化的算法是性能最优的字符串解决方案,但是开发测试量很大。

建议:输入输出和简单操作时候使用String

      复杂的更改使用StringBuilder

      极致性能要求时候:使用字符数组+算法

String类的静态缓冲池优化现象:

静态字符串:编译器能够确定内容的字符串

如:字符串面量、字符串常量、字面量常量的运算结果

相同静态字符串在运行期间引用同一个对象

Publicstatic final int ROWS=20

ROWS:称为常量,常量是一个名字

20:称为字面量

字面量和常量是不同的

经典面试题:字符串是为了“性能”进行优化

1、考察字符串的静态连接过程

Strings=new String(“123”+“ABC”);

这个代码在“运行期间”会出现几个String对象?

答案:2个字符串对象,静态字符串连接一个,又new出来一个

2、考察字符串的静态连接过程

A、String sql=”select *from emp where id=?”

   B、String sql=”select *“+

                       “from emp“+

                        ”where id=?”

   C、StringBuilder buf=newStringBuilder();

     Buf.append(”select *“)

          .append(“from emp“)

          .append(”where id=?”);

问题:A、B、C运行性能有差别吗?

答案:A、B性能没有差别,C运行期间执行,性能差。因为StringBuilder适合用来处理动态字符串,对于这种不变的字符串,性能差。

3、考察字符串的动态连接过程

String s=”123”;

String ss=s+”abc”;

1)、运行期间有几个字符串对象?

答案:3

“123”是一个,“abc”是一个,连接起来是一个“123abc”

2)、运行期间至少有几个对象?

答案:4个,因为连接符+实质上是调用的StringBuilder对象,为什么说至少呢,因为StringBuilder里面还调用了别的对象。

“123”、“abc”、“123abc”、newStringBuilder()






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值