1.常见字符串的三种方法
public class TestDemo {
public static void main(String[] args) {
String name="tjg";
System.out.println(name);
String name1=new String("tjg1");
System.out.println(name1);
char[] array={'a','b','c'};
String name3=new String(array);
System.out.println(name3);
}
}
在java中,不像C语言,不是通过/0来判断字符串结束,而是通过长度来判断字符串的结束。
1. String是引用类型,内部并不存储字符串本身,在String类的实现源码中,String类实例变量如下:
先写代码:
String s1=new String("hello");
String s2=new String("world");
String s3=s1;
具体的情况就二如同上图一般。但是虽然s1和s3指向同一个地址,之后都是指向的hello,但是在Java当中的字符串市字符串常量值,是不可以进行修改的。
2. 在Java中“”引起来的也是String类型对象
// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());
2.String对象的比较
字符串的比较是常见操作之一,比如:字符串排序。Java中总共提供了4种方式:
==比较是否引用同一个对象
public static void main(String[] args) {
String str1="hello";
String str2="hello";
System.out.println(str1==str2);
String s3=new String("hello");
String s4=new String("hello");
System.out.println(s3==s4);
}
前面的结果是true,但是后面的结果是flase,为什么呢?在str1和2里面的内容是一样的,所以结果是true,但是在s3和s4之中,只要是new了,就会开辟一个新的空间,s3和s4是存的不同对象的地址,所以结果是flase。那怎么比较两个里面的内容呢?代码如下:
System.out.println(s3.equals(s4));
这个的结果是用来比较里面的内容是否相同,但是如果是object类的话是不一样的,因为object用equal进行比较的时候,也是比较的地址,除非你重写比较方法。
你可以使用的比较方法:
System.out.println(s3.equals(s4));
System.out.println(s3.compareTo(s4));
但似乎用一个特殊的比较方法:我下面先来展示一下代码:
System.out.println(str1==str2);
String s3=new String("hello");
String s4=new String("Hello");
System.out.println(s3.equalsIgnoreCase(s4));
这个equalsIgnoreCase是忽视大小写,结果也是true。
3.字符串查找
此时的参数 需要是一个合法下标
public static void main(String[] args) {
String str="hello";
char ch=str.charAt(1);
System.out.println(ch);
}
这个是用来显示某个下标的位置是啥。
下面还有一个办法来找某个字符或者字符串所在的位置,代码如下:
public static void main(String[] args) {
String str="hello";
//char ch=str.charAt(1);
int ch=str.indexOf("l");
System.out.println(ch);
}
如果找不到的话会返回-1;下面我用一个图来展示一下这些重载的方法:
4.转化
1.数值和字符串的相互转换
public static void main(String[] args) {
double a=10.99;
String str=String.valueOf(a);
System.out.println(str);
String str1="1223";
int i=Integer.valueOf(str1);
i+=1;
System.out.println(i);
int ret2=Integer.parseInt(str1);
i+=1;
System.out.println(i);
}
2.大小写转换
public class TestDemo {
public static void main(String[] args) {
String s1="hello";
String s2="Hello";
System.out.println(s1.toUpperCase());
System.out.println(s2.toLowerCase());
System.out.println(s1);
}
}
这是代码,但是当你输出你会发现,你不是把s1的小写改成大写了吗,但是为什么输出的s1还是小写,其实这个代码更改可以说是新创了一个空间来存放更改之后的结果,而不是直接更改s1.这个只是把大写字面或者小写字母进行了更改,如果里面放入了其他的不会进行变化。
3.字符串和数组之间的转换
public class TestDemo {
public static void main(String[] args) {
String s1="hello";
char[] chars=s1.toCharArray();
System.out.println(Arrays.toString(chars));
String s2=new String(chars);
System.out.println(s2);
}
4.格式化
String s = String.format("%d-%d-%d", 2019, 9,14); System.out.println(s);
5.字符串的替换
public static void main(String[] args) {
String str1="ababcabcd";
String s2=str1.replace("a","e");
System.out.println(s2);
}
在Java中所有的对字符喜欢的操作都不会对原来的字符串进行操作,因为字符串是不可变的。
6.字符串的拆分
先简单的演示一下,一个字符用“ ”来拆分的代码:
String str1="ni hao ya";
String[] s1=str1.split(" ");
System.out.println(Arrays.toString(s1));
for (String s:s1) {
System.out.println(s);
}
如果又有=又有空格那怎么办呢?代码如下:
String str2="ni=shi zhen=sha";
String[] s2=str2.split(" ");
for (String s:s2) {
String[] s3=s.split("=");
for (String s4:s3) {
System.out.println(s4);
}
}
或者这样:
String[] s5=str2.split(" |=");
for (String s:s5) {
System.out.println(s);
}
拆分是特别常用的操作. 一定要重点掌握. 另外有些特殊字符作为分割符可能无法正确切分, 需要加上转义.
代码示例: 拆分IP地址
String s6="192.116.1.1";
String[] s7=s6.split("\\.");
for (String s:s7) {
System.out.println(s);
}
注意事项:
1. 字符"|","*","+"都得加上转义字符,前面加上"\\".
2. 而如果是"\",那么就得写成"\\\\".
3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符.
7.字符串的截取
public class TestDemo {
public static void main(String[] args) {
String str="ababcabcd";
String s1=str.substring(2);
String s2=str.substring(2,5);
System.out.println(s1);
System.out.println(s2);
}
}
在substring里面如果只有一个数字,代表是从该数字下标开始截取,如果是有两个数字代表是从前面一个数字开始,后面一个数字结束,左闭右开。范围必须合法
注意事项:
1. 索引从0开始
2. 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标
8.其他操作方法
public static void main(String[] args) {
String s1=" ab abc ";
String s2=s1.trim();
System.out.println(s2);
}
trim去除字符串左右两边的空格,但是中间的空格不会去除。
public static void main(String[] args) {
String s1="abcDe";
String s2=s1.toLowerCase();
String s3=s1.toUpperCase();
System.out.println(s2);
System.out.println(s3);
}
toLowerCase:大写全部转换成小写,
toUpperCase:小写全部转换成大写。
9.常量池
public class TestDemo {
public static void main(String[] args) {
String str1="hello";
String str2="hello";
System.out.println(str1==str2);
String str3=new String("hello");
System.out.println(str1==str3);
}
}
当这个代码走完你会产生疑问,为什么str1=str2,但是后面就不相等呢?
当你看完下面你就会知道具体的原因是什么。
首先要先引入一个概念叫做常量池,StringTable【常量池】,StringTable是哈希表。
为什么会有常量池这个概念产生呢?主要的目的就是为了使程序的运行速度更快、更节省内存,下面先简单的了解认识一下三个池:
1. Class文件常量池:每个.Java源文件编译后生成.Class文件中会保存当前类中的字面常量以及符号信息
2. 运行时常量池:在.Class文件被加载时,.Class文件中的常量池被加载到内存中称为运行时常量池,运行时常量池每个类都有一份
3. 字符串常量池
字符串常量池(StringTable)
字符串常量池在JVM中是StringTable类,实际是一个固定大小的HashTable
注意:
1. 在JVM中字符串常量池只有一份,是全局共享的
2. 刚开始字符串常量池是空的,随着程序不断运行,字符串常量池中元素会越来越多
3. 当类加载时,字节码文件中的常量池也被加载到JVM中,称为运行时常量池,同时会将其中的字符串常量保存在字符串常量池中
4. 字符创常量池中的内容:一部分来自运行时常量池,一部分来自程序动态添加
注意一下我上面加粗部分的内容,一开始常量池也是空的,是随着程序的不断运行,使得字符串常量池里面的元素越来越多。
下面展示一下用new来创建对象时候的过程。
那怎么才能让我一开始的那个str1=str3呢?
下面我们讲到的intern方法就可以解决这个问题,通过这个方法,可以使得把new的对象也放入到常量池中(前提是目前常量池中没有这个)。
public class TestDemo {
public static void main(String[] args) {
char[] ch={'h','e','l','l','o'};
String str3=new String(ch);
str3.intern();
String str1="hello";
String str2="hello";
System.out.println(str1==str2);
System.out.println(str1==str3);
}
}
10.字符串的不可变性
String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:
1. String类在设计时就是不可改变的,String类实现描述中已经说明了
String类中的字符实际保存在内部维护的value字符数组中,该图还可以看出:
1. String类被final修饰,表明该类不能被继承
2. value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。
2. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
【纠正】网上有些人说:字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变。
这种说法是错误的,不是因为String类自身,或者其内部value被final修饰而不能被修改。
final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。
11 字符串修改
注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。
public static void main(String[] args) {
String str="hello";
str+="world";
System.out.println(str);
}
借助StringBuilder和StringBuffer
12.StringBuilder和StringBuffer
public static void main(String[] args) {
StringBuffer str1=new StringBuffer("hello");
StringBuffer str2=str1;
str1.append(" ");
str1.append("world");
System.out.println(str1);
System.out.println(str2);
}
使用StringBuilder和StringBuffer不会进行新的创建,会直接在原有的上面进行删改。
从上述例子可以看出:String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改。频繁修改字符串的情况考虑使用StringBuilder。
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
StringBuilder变为String: 调用toString()方法。
String、StringBuffer、StringBuilder的区别
String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
StringBuffer与StringBuilder大部分功能是相似的
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作