前言
一、Sting类型简介
字符串定义
字符串类型:String。这个类不可以被继承(被final修饰),支持比较大小。
三种初始化方式:
public class Test04 {
String str="hello";//1
String str1=new String("hello");//2
char[] chars={'a','j','d'};
String str3=new String(chars);//3
}
java中没有说过字符串是以’\0’结尾的。
用string.length可以得到字符串长度。
注意:str指向的对象没有任何数据
str5代表不指向任何对象。
字符串空串和空指针
public class Test04 {
public static void main(String[] args) {
String str="";//1
String str1=null;//2
System.out.println(str.isEmpty());
System.out.println(str1.isEmpty());
}
}
对应未知的字符串,或是字符串传参,要记得判断是否为空或是长度是否为0.
if(str==null){return 0}
if(str.length==0){return 0}
字符串的等价比较
因为new的指向不同对象空间,存的地址不同,而后面是指向同一个“abc”,存的相同。使用 == 比较字符串是比较对象的地址, 而不是字符串的具体内容是否相同。equal是比较值是否相同。
public class Test04 {
public static void main(String[] args) {
String str=new String("abc");//1
String str1=new String("abc");//2
System.out.println(str==str1);
String str2="bcd";
String str3="bcd";
System.out.println(str2==str3);
}
}
二、String类各种方法
字符串的不可变性:所有对字符串的操作或修改都不是在原来值的基础上,而是new了一个新的对象。主要是它被private修饰。
要修改就要用到反射。(后面会讲到)
1.字符串比较
compareTo
比较大小:
String str=new String("abcds");//1
String str1=new String("ahc");//2
System.out.println(str.compareTo(str1));
1<2返回负数;1>2返回正数;1=2返回0.
忽略大小写比较compareToIgnoreCase
相等为0
String str=new String("abcds");//1
String str1=new String("aBCds");//2
System.out.println(str.compareToIgnoreCase(str1));
2.字符串查找
1.charAt()
String str=new String("abcds");
System.out.println(str.charAt(1));//b
2.indexof()
返回指定的字符第一次出现的位置
String str=new String("abcds");
System.out.println(str.indexOf("c"));//2
System.out.println(str.indexOf("c",3));//-1.没找到,从3开始找
System.out.println(str.indexOf("cds"));//2,查找字符串
String str=new String("abcsss");
System.out.println(str.lastIndexOf("s"));//数的是最后一个的S,从后往前走。
lastIndexof
String str=new String("abcsss");
System.out.println(str.lastIndexOf("s"));//数的是最后一个的S,从后往前走。//5
System.out.println(str.lastIndexOf("s",4));//从4坐标往前数。//4
3.将其他数据类型转为字符串(valueof)
1.整形等基本数据类型
int str2=222233;
System.out.println(String.valueOf(str2));
2.类的对象
class Animal {
int age;
String name;
int sex;
public Animal(int age, String name, int sex) {
this.age = age;
this.name = name;
this.sex = sex;
}
@Override
public String toString() {
return "Animal{" +
"age=" + age +
", name='" + name + '\'' +
", sex=" + sex +
'}';
}
}
public class Test05{
public static void main(String[] args) {
Animal animal=new Animal(3,"红花",2);
System.out.println(String.valueOf(animal));
}
}
未重写toString输出:
重写后输出:因为valueof有继承tostring,所以可以调用重写的toString。
4.String类型转数组类型(toCharArray())
String str=new String("AbCDddFSss");
char[] ret=str.toCharArray();
System.out.println(Arrays.toString(ret));//[A, b, C, D, d, d, F, S, s, s]
5.String大小写转换
变大写toUpperCase
String str=new String("abcsss");
String ret=str.toUpperCase();
System.out.println(ret);//ABCSSS
变小写toLowerCase
String str=new String("AbCDddFSss");
String ret=str.toLowerCase();
System.out.println(ret);//abcdddfsss
6.字符串替换
replace
String str=new String("AbssCsfdsDddFSss");
String ret=str.replace("s","u");
System.out.println(ret);//AbuuCufduDddFSuu
replaceFirst
替换出现的第一个字符段。
String str=new String("AbssssCsfdsDddFSssCc");
String ret=str.replaceFirst("ssC","uh");
System.out.println(ret);//AbssuhsfdsDddFSssCc
replaceAll
所有的字段都用另一个字段来替换
String str=new String("AbssssCsfdsDddFSssCc");
String ret=str.replaceAll("ssC","uh");
System.out.println(ret);//AbssuhsfdsDddFSuhc
7.字符串拆分(split)
根据指定的字符对字符串进行分割,分割之后的返回值就是数组。
String str=new String("Absss sCs fds Ddd FSs sCc");
String[] ret=str.split(" ");
for (int i = 0; i < ret.length; i++) {
System.out.print(ret[i]+",");//Absss,sCs,fds,Ddd,FSs,sCc,222233
}
如果限定了只分两组,就不会均分。
String[] ret=str.split(" ",2);
for (int i = 0; i < ret.length; i++) {
System.out.print(ret[i]+",");//Absss,sCs fds Ddd FSs sCc,
}
注意:拆分时如果是有特殊字符要注意转义及其规则:
\的分和写
String str=new String("Absss\\sCs\\fds\\Ddd\\FSs\\sCc");//两个斜杠才能表示1个
System.out.println(str);//Absss\sCs\fds\Ddd\FSs\sCc
String[] ret=str.split("\\\\");
for (int i = 0; i < ret.length; i++) {
System.out.print(ret[i]+",");//Absss,sCs,fds,Ddd,FSs,sCc,
}
以|可以按多个分割符划分
String str=new String("Absss&sCs=fds=Ddd&FS&sCc");
String[] ret=str.split("&|=");
for (int i = 0; i < ret.length; i++) {
System.out.print(ret[i]+",");//Absss,sCs,fds,Ddd,FS,sCc,
}
如果有多个分割符也可每一个分隔符拆分一次,进行多次拆分。
8.字符串的截取
1.可以截取指定位置开始的剩余字符串
2.截取指定位置到指定位置的字符串,左闭右开
substring()
String str=new String("Absss&sCs=fds=Ddd&FS&sCc");
String ret=str.substring(1);//截取指定位置开始的剩余字符串
System.out.println(ret);//bsss&sCs=fds=Ddd&FS&sCc
String ret=str.substring(1,6);//截取指定位置到指定位置的字符串,左闭右开
System.out.println(ret);//bsss&//[1,6)
trim()
去除字符串左右空格
String str=new String(" Absss ss= fds =DFS&s Cc ");
String ret=str.trim();//去除左右空格
System.out.println(ret);//Absss ss= fds =DFS&s Cc
System.out.println(str);// Absss ss= fds =DFS&s Cc
三、字符串的修改
String类型的字符串,不能够修改,每次增加拼接或则改动字符串都要重新new一个新的对象,因此很占内存,而且耗时。
而StringBuffer和StringBuilder是可以对字符串直接进行修改的。
StringBuilder与StringBuffer
StringBuilder与StringBuffer有很多都是相同的。这里相同用法的就只写其中之一了。在它们上对字符串进行改变就是对原来对象的改动,不会自动产生新的对象。
public static void main(String[] args) {
StringBuffer str=new StringBuffer("abcabcabcabc");
str.insert(1,"jrhfbh");
System.out.println(str);//ajrhfbhbcabcabcabc//将字符插入1
str.delete(1,5);
System.out.println(str);//abhbcabcabcabc//删除[1,5)的字符
System.out.println(str.reverse());//cbacbacbacbhba//字符串逆置
System.out.println(str.append("hdghxsh"));//cbacbacbacbhbahdghxsh//字符串增加
String str2=str.toString();//将StringBuffer类型以String类型返回
}
区别:
synchronized(同步锁)–>多线程下使用,为了线程的安全性,相当于一把锁。–》保证在同一时刻被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果。但是每次频繁的加锁和解锁很浪费资源。
StringBuffer的append被synchronized修饰,属于线程安全操作,但是StringBuilder没有。因此在不考虑线程安全的情况下,使用StringBuilder更好。
三种字符串类型相互转换
将String类型转变为StringBuilder,利用StringBuilder的构造方法或append()方法。
StringBuilder str2=new StringBuilder("udwcwghd");
str2.append("shbs");
将StringBuffer转变为String
String str2=str.toString();//将StringBuffer类型以String类型返回
四、String题
引用指向对象问题
指出下列程序运行的结果()good and gbc
public class Example{
String str = new String("good");
char[ ] ch = { 'a' , 'b' , 'c' };
public static void main(String args[]){
Example ex = new Example();
ex.change(ex.str,ex.ch);
System.out.print(ex.str + " and ");
System.out.print(ex.ch);
}
public void change(String str,char ch[ ]){
str = "test ok";
ch[0] = 'g';
}
}
字符串的不可变
下面代码将输出什么内容:()false
public class SystemUtil{
public static boolean isAdmin(String userId){
return userId.toLowerCase()=="admin";
}
public static void main(String[] args){
System.out.println(isAdmin("Admin"));
}
}
==号两边的是引用数据类型,那么比较的是"地址相不相同"。“admin”,存放在常量池当中,但是通过方法,userId.toLowerCase()。返回的是一个新的对象。通过字符串的不可变性,可知新的肯定和原来的地址不同。
大写转小写
给你一个字符串 s ,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。
示例 1:输入:s = "Hello"输出:“hello”
分析:
大写A:65
小写a: 97
相差32
public class Test07{
public static void main(String[] args) {
String str1="FdhkAbsDFWSFceKLfk";
char [] arr=str1.toCharArray();
for (int i = 0; i < arr.length; i++) {
char ch=arr[i];
if(ch>='A'&&ch<'a'){
ch+=32;
arr[i]=ch;//直接赋值取代
}
}
String str2=new String(arr);//初始化
System.out.println(str2);//fdhkabsdfwsfceklfk
}
}
这道用一个toLowerCase就能解决,但是极度不推荐。
找第一个只出现字符
该字符串全小写,找第一个只出现字符。
1.统计每个单词的次数
2.遍历字符串,看每个字符的次数。
public static void main(String[] args) {
String str="shbbhsjsl";
int []count=new int[26];
for (int i = 0; i < str.length(); i++) {
char ch=str.charAt(i);
count[ch-'a']++;
}
for (int i = 0; i < 26; i++) {
if(count[i]==1)
{
System.out.println((char)(i+97));
break;
}
}
}
还有更优法,用哈希表,以后会写到。与次数,频率相关的都能够用哈希表最好。
计算字符串最后一个单词的长度
每个单词以空格隔开。
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while (sc.hasNextLine()){
String str=sc.nextLine();
int index=str.lastIndexOf(" ");//最后一个空格为已知元素,可以为此求下标。
String tmp=str.substring(index+1);//利用下标直接截取最后一个单词
System.out.println(tmp);
}
}
回文串
如果将所有大写字符转换为小写字符,并移除所有非字母非数字字符之后,短语正反读一样为回文串(只有字母和数字)。
Character.isLetter(char ch)//判断是否是字符
Character.isDigit(char ch)//判断是否是数字
import java.util.Scanner;
class Solution{
public boolean isPalindrome(String s){
s=s.toLowerCase();
int left=0;
int right=s.length()-1;
while(left<right){
while(left<right&&!isVaildChar(s.charAt(left))){
left++;
}
while (left<right&&isVaildChar(s.charAt(right))){
right--;
}
if(s.charAt(left)!=s.charAt(right)){
return false;
}
else{
left++;
right++;
}
}
return true;
}
private boolean isVaildChar(char ch){
if(Character.isDigit(ch)||Character.isLetter(ch)){
return true;
}
else{
return false;
}
}
}
总结
1.笔试时除非时间非常紧张,没有时间思考可以直接调用库方法完成,否则就自己正常写。
2.在面试时发现一个库方法就能解决,往往不能用库方法。
因为直接调用库方法就能解决体现不出自己的逻辑。
可以借用库方法,但不能完成靠库方法。
面试,手写代码。