目录
2.1、==比较是否变量中的值
2.2、 boolean equal(Object anObject)方法,按照字典序(字符大小顺序)比较
2.4、compareToIgnoreCase方法:忽略大小写比较
4.1、数值和 字符串 转化
5.5、contains是否包含某内容
8、 StringBuilder 和StringBuffffer
总结StringBuilder与String类的区别
题目一:字符串中的第一个唯一字符
题目二:字符串最后一个单词的长度
题目三:检测字符串是否为 回文
string 类,在 Java 中属于字符串类型。
1、字符串构造
常用的三种构造字符串的方式:
代码:
public class Test { | |
public static void main(String[] args) { | |
//方法一: | |
String str1="happy";//str是一个引用变量,happy属于字符串常量 | |
System.out.println(str); | |
//方法二: | |
String str=new String("lyj"); | |
System.out.println(str); | |
//方法三 | |
char[] ch={'l','o','n','g'};// 字符数组 | |
String str=new String(ch); | |
System.out.println(str); | |
} | |
} |
运行结果:
补充:
String是引用类型,内部并不存储字符串本身
查看String类,会看到他有两个属性
比如我们看例中的happy的内存分布:
2、String对象的比较
2.1、==比较是否变量中的值
例:
public class Test { | |
public static void main(String[] args) { | |
int a=; | |
int b=; | |
int c=; | |
System.out.println(a==b); | |
System.out.println(a==c); | |
} | |
} |
运行结果如下:
但是这个比较只针对内置类型,对于引用类型,这么比较就是错误的,因为他比较的是值,也就是比较的是引用中的地址,并没有比较其指向的内容
2.2、boolean equal(Object anObject)方法,按照字典序(字符大小顺序)比较
String类重写了父类Object中的Equals方法,Object中equals默认是==比较,源码:
而String重写,源码:
按照以下规则比较:
例:
public class Test { | |
public static void main(String[] args) { | |
String str="lyj"; | |
String str="lya"; | |
String str="lyj"; | |
System.out.println(str.equals(str2)); | |
System.out.println(str.equals(str3)); | |
} | |
} |
运行:
2.3、compareTo方法:
查看String中compareTo方法源码:
例:
public static void main(String[] args) { | |
String str="lyj"; | |
String str="lya"; | |
String str="lyj"; | |
int ret=str1.compareTo(str2); | |
if(ret>0) { | |
System.out.println("str>str2"); | |
} else if(ret==0) { | |
System.out.println("str=str2"); | |
} else { | |
System.out.println("str<str2"); | |
} | |
int ret=str1.compareTo(str3); | |
if(ret>0) { | |
System.out.println("str>str3"); | |
} else if(ret==0) { | |
System.out.println("str=str3"); | |
} else { | |
System.out.println("str<str3"); | |
} | |
} |
运行结果:
2.4、compareToIgnoreCase方法:忽略大小写比较
例:
public static void main(String[] args) { | |
String str="lyj"; | |
String str="LYJ"; | |
System.out.println(str.equalsIgnoreCase(str2)); | |
} |
运行结果:
3、字符串查找
常用的方法总结:
方法 | 功能 |
char charAt(int index) | 放回index位置上字符,如果index为负数或者越界,抛出indexOutOfBounds Exception 异常 |
int indexOf(int ch) | 返回ch第一次出现的位置,没有返回-1 |
int intdexOf(int ch,int fromIndex) | 从fromIndex位置开始找ch第一次出现的位置,没有返回-1 |
int indexOf(String str) | 返回 dtr 第一次出现的位置,没有返回-1 |
int indexOf(String str,int fromIndex) | 从fromIndex位置开始找str第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch) | 从后往前找,返回ch第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch,int | 从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1 |
int lastIndexOf(String str) | 从后往前找,返回 str 第一次出现的位置,没有返回 -1 |
int lastIndexOf(String str, int fromIndex) | 从 fromIndex 位置开始找,从后往前找 str 第一次出现的位置,没有返 回 -1 |
范例:
public static void main(String[] args) { | |
String str="abcdcf"; | |
for (int i =; i < str.length(); i++) { | |
char ch=str.charAt(i); | |
System.out.print(ch+" ");//a b c d e f | |
} | |
System.out.println(); | |
System.out.println(str.indexOf('d'));// | |
System.out.println(str.indexOf('c',));//4 | |
String str="abclyjdcef"; | |
System.out.println(str.indexOf("lyj"));//3 | |
System.out.println(str.indexOf("lyj",4));//-1 | |
System.out.println(str.lastIndexOf('c'));//7 | |
System.out.println(str.lastIndexOf('c',4));//2 | |
System.out.println(str.lastIndexOf("lyj"));//3 | |
System.out.println(str.lastIndexOf("lyj",6));//3 | |
} |
4、转化
4.1、数值和字符串转化
public static void main(String[] args) { | |
//其他类型转换为字符串 | |
String str=String.valueOf(410); | |
String str=String.valueOf('l'); | |
String str=String.valueOf(3.14); | |
String str=String.valueOf(3.5f); | |
String str=String.valueOf(false); | |
String str=String.valueOf(new Person("jingjing",18)); | |
System.out.println(str+" "+str2+" "+str3+" "+str4+" "+str5+" "+str6);//410 l 3.14 3.5 false Person{name='jingjing', age=18} | |
//字符串转换为其他类型 | |
int val=Integer.valueOf(""); | |
int val=Integer.parseInt("318"); | |
double val=Double.parseDouble("3.14"); | |
float val=Float. parseFloat ("3.5f"); | |
System.out.println(val+" "+val+" "+val2+" "+val3);//410 318 3.14 3.5 | |
} |
4.2、大小写转换
public static void main(String[] args) { | |
String str="family"; | |
System.out.println(str.toUpperCase());//FAMILY | |
String str="LOVE"; | |
System.out.println(str.toLowerCase());//love | |
} |
4.3、字符串转数组
public static void main(String[] args) { | |
//字符串转数组 | |
String str="today is so..."; | |
char[] chars=str.toCharArray(); | |
for (int i =; i < str1.length(); i++) { | |
System.out.print(chars[i]+" ");//t o d a y i s s o . . . | |
} | |
//数组转字符串 | |
String str=new String(chars); | |
System.out.println(str);//today is so... | |
} |
4.4、格式化
public static void main(String[] args) { | |
String s = String.format("%d-%d-%d",, 8,12); | |
//有点类似于 printf | |
System.out.println(s);//-8-12 | |
} |
5、常用方法
5.1、字符串替换
方法 | 功能 |
String replace(char oldChar,char newChar) | 替换指定字符 |
String replace(String target,String replacement) | 替换指定内容 |
String replaceAll(String regex, String replacement) | 替换所有的指定内容 |
String replaceFirst(String regex, String replacement) | 替换收个内容 |
范例:
public static void main(String[] args) { | |
String str="ablyjlyjablyjabcdef"; | |
String ret=str.replace('l','k'); | |
System.out.println(ret);//abkyjkyjabkyjabcdef | |
ret=str.replace("lyj","cyk"); | |
System.out.println(ret);//abcykcykabcykabcdef | |
ret=ret.replaceFirst("cyk","lyj"); | |
System.out.println(ret);//ablyjcykabcykabcdef | |
ret=ret.replaceAll("cyk","lyj"); | |
System.out.println(ret);//ablyjlyjablyjabcdef | |
} |
5.2、字符串拆分
方法 | 功能 |
String[] split(String regex) | 将字符串全部拆分 |
String[] split(String regex, int limit) | 将字符串以指定的格式,拆分为limit组 |
public static void main(String[] args) { | |
String str="lyjhhh@ccykee"; | |
String[] ret=str.split("@"); | |
System.out.println(Arrays.toString(ret));//[lyjhhh, ccykee] | |
str="lyj@cyk&lyz@lxm"; | |
ret=str.split("@",); | |
System.out.println(Arrays.toString(ret));//[lyj, cyk@lyz@lxm] | |
} |
注: 如果一个字符串中有多个分隔符,可以用 “|” 作为 连字符 .
public static void main(String[] args) { | |
String str="lyz&cyk*lyj@lxm"; | |
String[] ret=str.split("&|@"); | |
System.out.println(Arrays.toString(ret));//[lyz, cyk*lyj, lxm] | |
} |
5.3、字符串截取
方法 | 功能 |
String substring(int beginIndex) | 从指定索引截取到结尾 |
String substring(int beginIndex, int endIndex) | 截取部分内容 |
范例:
public static void main(String[] args) { | |
String str="helloworld"; | |
String ret=str.substring(1); | |
System.out.println(ret);//elloworld | |
String ret=str.substring(1,5);//前开后闭 | |
System.out.println(ret);//ello | |
} |
5.4、trim空格字符处理
String trim() 功能:
去掉字符串中的左右空格 , 保留中间空格
范例:
public static void main(String[] args) { | |
String str=" hello world "; | |
String ret=str.trim(); | |
System.out.println(ret);//hello world | |
} |
5.5、contains是否包含某内容
判断是否包含某字符串
public static void main(String[] args) { | |
String str="hellolyjhahaha"; | |
System.out.println(str.contains("lyj"));//true | |
} |
6、字符串常量池
字符串常量池,其底层是一个StringTable的哈希表
通俗的来说,就是为了使程序运行得更快,更加节省内存,Java就引出了,池的概念,而 字符串常量 池,就是存放一些我们常用的字符串,其由 双引号 括起来的,例:
String str =" lyj ";
其内存布局:
注:上述提到过的,String类有两个属性,一个value,一个 hash
在字符串常量池中,没有对应的字符串时,将其存入,如果有了,则就会使用那一份现有的数据。
根据上述提示,分析下面的代码运行结果:
public static void main(String[] args) { | |
String str="lyj"; | |
String str="lyj"; | |
String str=new String("lyj"); | |
String str=new String("lyj"); | |
System.out.println(str==str2);//true | |
System.out.println(str==str4);//false | |
System.out.println(str==str3);//false | |
} |
内存布局分析:
补充: intern方法
该方法的作用是手 动将创建的 String 对象添加到常量池中 。
public static void main(String[] args) { | |
char[] ch=new char[]{'l','y','j'}; | |
String s=new String(ch);//没有入池 | |
s.intern();//入池 | |
String s="lyj"; | |
System.out.println(s==s2);//true | |
char[] ch=new char[]{'a','b','c'}; | |
String s=new String(ch1); | |
String s="abc"; | |
System.out.println(s==s4);//false | |
} |
面试题:
请解释String类中两种对象实例化的区别(常量池中都不存在以下字符串)
JDK 1.8中
提示:根据上述例中的内存图,可知,每创建一个字符串对象时,有一个value和一个hash,
value 又指 向对应的字符串,一共两个对象
1. String str = “hello”
正解:2
只会开辟一块堆内存空间,保存在字符串常量池中,然后str共享常量池中的String对象
2. String str = new String(“hello”)
正解:3
会开辟两块堆内存空间,字符串”hello”保存在字符串常量池中,然后用常量池中的String对象
给新开辟 的String对象赋值。
3. String str = new String(new char[]{‘h’, ‘e’, ‘l’, ‘l’, ‘o’})
正解:3
现在堆上创建一个String对象,然后利用copyof将重新开辟数组空间,将参数字符串数组中内
容拷贝到 String对象中
7、字符串的不可变性
String类不可变的原因:
1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
2. 不可变对象是 线程 安全的.
3. 不可变对象更方便缓存 hash code , 作为 key 时可以更高效的保存到 HashMap 中.
从哪儿观察到不可变呢?观察其源码:
而我们在上述的方法中, 提到的所有关于会改变字符串的方法,他其实都是新创建了一个对象
看以下代码 :
public static void main(String[] args) { | |
String str="*"; | |
for (int i =; i < 20; i++) { | |
str+=i; | |
} | |
System.out.println(str);//* | |
} |
我们去查看一下他的汇编:
由于效率太低,因此,引入另一种方法:
代码改进:
public static void main(String[] args) { | |
String str="*"; | |
StringBuilder stringBuffer=new StringBuilder(); | |
stringBuffer .append(str); | |
for (int i =; i < 20; i++) { | |
stringBuffer.append(i); | |
} | |
System.out.println(stringBuffer);//* | |
} |
不太明白吧?继续向下看咯:
8、StringBuilder和StringBuffffer
StringBuilder 和 StringBuffffer也可以表示字符串,但他们不能直接赋值
使用举例:
public static void main(String[] args) { | |
StringBuilder stringBuilder=new StringBuilder("love"); | |
System.out.println(stringBuilder);//love | |
stringBuilder.reverse(); | |
System.out.println(stringBuilder);//evol | |
} |
这个字符串逆序,String类是没有这个方法的
从这可以观察到, StringBuilder 和StringBuffffer 与String类的区别,String对字符串内容变动时,都是需要新创建一个对象,并需要接收这个对象,而 StringBuilder 和 StringBuffffer 它们是对相应的字符串本身进行修改的,因此不需要接收。
总结StringBuilder与String类的区别
String:
1.String创建的对象是不可变的,一旦创建不可改变
2.对象值可以改变其实是创建了一个新的对象,然后把新的值保存进去
3.String类被final修饰,不可以被继承
4.String创建的对象的值存在于常量池,不用的时候不会被销毁
5.String运行时间较长
6.String适用于比较短而小的字符串
StringBuffer
1.StringBuffer创建的对象是可变的
2.它的改变不像String那样重新创建对象,而是通过构造方法
3.StringBuffer创建的对象的值存在于栈区,不用的时候会被销毁
4.StringBuffer运行时间较短
5.StringBuffer适用于比较长的字符串、比较多的字符串
StringBuilder 具体其他的方法,可以查看文档:http:// StringBuilder在线文档
补充:1、String与StringBuilder相互转换:
public static void main(String[] args) { | |
String str="love"; | |
StringBuilder stringBuilder=new StringBuilder(str);//String变成了StringBuilder | |
System.out.println(stringBuilder); | |
} | |
StringBuilder s = new StringBuilder("nice"); | |
String s = s.toString(); |
面试题:
1. String 、 StringBuffffer 、 StringBuilder 的区别?
String的内容不可修改,StringBuffffer与StringBuilder的内容可以修改.
StringBuffffer与StringBuilder大部分功能是相似的
StringBuffffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程
不安全操 作
2. 以下总共创建了多少个 String 对象【前提不考虑常量池之前是否存在】
String str = new String ( “ab” ); // 会创建 2个对象
String str = new String ( “a” ) + new String ( “b” ); // 会创建 6个对象
第二题的不理解看图:
toString转换会new新的对象:
9、OJ题巩固
题目一:字符串中的第一个唯一字符
题目描述:
两次遍历
count为计数数组(利用ASCII码,a对应97),一开始创建的count数组,里面所有值默认为0
第一次遍历, 用字符的ASCII码减去’a’,得到的下标就与计数数组对应上了,将其加一
第二次遍历,将第一个为1的返回即可
代码:
class Solution { | |
public int firstUniqChar(String s) { | |
int[] count=new int[]; | |
for(int i=;i<s.length();i++) { | |
char ch=s.charAt(i); | |
count[ch-'a']++; | |
} | |
for(int i =;i<s.length();i++) { | |
char ch=s.charAt(i); | |
if(count[ch-'a']==) { | |
return i; | |
} | |
} | |
return -; | |
} | |
} |
测试通过:
题目二:字符串最后一个单词的长度
解法一:找到最后一个空格的位置,用总长度减去即可
代码:
import java.io.InputStream; | |
import java.util.Scanner; | |
public class Main{ | |
public static void main(String [] args) throws Exception{ | |
Scanner sc=new Scanner(System.in); | |
String str= sc.nextLine(); | |
int n=str.lastIndexOf(' '); | |
int x=str.length(); | |
System.out.println(x-n-); | |
} | |
} |
测试通过:
解法二:用字符串分割方法,输出其数组的最后一个字符串的长度
代码:
import java.io.InputStream; | |
import java.util.Scanner; | |
public class Main{ | |
public static void main(String [] args) throws Exception{ | |
Scanner sc=new Scanner(System.in); | |
String str= sc.nextLine(); | |
String[] ret=str.split(" "); | |
System.out.println(ret[ret.length-].length()); | |
} | |
} |
测试通过:
题目三:检测字符串是否为回文
题目描述:
思路在代码中有注释:
代码:
class Solution { | |
//有效字符判断 | |
public boolean isEffective(char ch) { | |
return Character.isLetterOrDigit(ch); | |
} | |
public boolean isPalindrome(String s) { | |
//统一大小写 | |
s=s.toLowerCase(); | |
int right=s.length()-; | |
int left=; | |
//回文判断 | |
while(left<right) { | |
while(left<right&&!isEffective(s.charAt(left))) { | |
left++; | |
} | |
while(left<right&&!isEffective(s.charAt(right))) { | |
right--; | |
} | |
if(s.charAt(left)!=s.charAt(right)) { | |
return false; | |
} | |
left++; | |
right--; | |
} | |
return true; | |
} | |
} |
测试通过: