1. String类的两种实例化方式
a. 直接赋值
b. 构造方法实例化
public class Test4{
public static void main(String[] args){
//直接赋值。在堆上分配空间
String str = "Hello";
//通过构造方法实例化String对象
String str1 = new String("Hello!");
}
}
两种实例化方式的区别在下面会讲到。
2. 字符串相等比较
先来看基本数据类型的比较
public class Test4{
public static void main(String[] args){
int i1 = 10;
int i2 = 10;
System.out.println(i1 == i2); // 输出为true
}
}
观察字符串“ == ”比较
public class Test4{
public static void main(String[] args){
String str1 = "hello";
String str2 = new String("hello"); //str新开辟了一块堆地址,存放hello。
System.out.println(str1 == str2);
}
}
两个字符串内容相等,使用 == 比较得到的结果却不同,看如下的内存图分析:
==本身是进行数值比较的,如果现在用于对象比较,那么所比较的就应该是两个对象锁保存的内存地址数值,而并没有比较对象的内容。
我们其实有专门的比较方法(比较内容):
public boolean equals(String anotherString):
public class Test4{
public static void main(String[] args){
String str1 = "hello";
String str2 = new String("hello");
System.out.println(str1.equals(str2)); // true
}
}
3. String的匿名对象
在任何语言的底层,都不会提供有直接的字符串类型。现在所谓的字符串只是高级语言提供给用户方便开发的支持而已。在Java中,本身也没有直接提供字符串常量的概念,所有使用“ “定义的内容本质上来讲都是String的匿名对象。
要想证明字符串常量是String的匿名对象,字符串常量只要能调用对象的方法就可以。
public class Test4{
public static void main(String[] args){
String str1 = "hello";
String str2 = new String("hello");
System.out.println(str1.equals(str2));
System.out.println("hello".equals(str2)); //equals就是匿名对象的方法
}
}
这里有个小坑需要注意:
public class Test4{
public static void main(String[] args){
//用户若在输入时,不小心输为空指针
String str2 = null;
System.out.println(str2.equals("hello")); //编译通过,运行时报错"空指针异常"
System.out.println("hello".equals(str2)); //编译运行都通过,结果为false
}
}
tip::以后开发时,如果要判断用户输入的字符是否等同于特定字符串,一定要将特定字符串(String常量)写在前面,避免NullPointerException
4. 实例化的区别 对象入池
4.1 直接赋值
public class Test4{
public static void main(String[] args){
String str1 = "hello";
String str2 = "hello";
String str3 = "hello";
System.out.println(str1 == str2);
System.out.println(str1 == str2);
System.out.println(str1 == str2);
}
}
此时没有开辟新的内存空间是因为String类的设计使用了共享设计模式。
JVM底层会自动维护一个字符串的对象池(对象数组),如果现在采用直接赋值的形式进行String的对象实例化,该对象会自动保存在这个对象池之中。如果下次继续使用直接赋值的模式声明String对象,此时对象中若有指定内容,则直接引用;如果没有,则开辟新的堆空间后将其保存在对象池中供下次使用。
4.2 采用构造方法
String str = new String("hello");
通过分析可知,如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间。也会对字符串共享产生问题。
因此在String类中提供有方法入池的操作
public String intern( );
public native String intern();
public class Test4{
public static void main(String[] args){
String str1 = "hello";
String str2 = new String("hello").intern(); //手工入池
System.out.println(str1 == str2); //true
}
}
5. 字符串不可变更
字符串一旦定义后不可改变。
public class Test4{
public static void main(String[] args){
String str1 = "hello";
str1 += "world";
str1 += "!";
System.out.println(str1); //输出结果为helloworld!
}
}
可以发现字符串没有发生任何变化,但是字符串对象的引用一直在改变,而且会形成大量的垃圾空间。因此以下代码不应该出现在我们的开发中。
public class Test4{
public static void main(String[] args){
String str = "hello";
for(int i = 0; i<1000; i++){
str += i;
System.out.println(str);
}
}
}
- 字符与字符串
6.1 将字符数组转为字符串
public String(char[] value) 有参构造方法
//将字符数组转为字符串
public class Test6{
public static void main(String[] args){
char[] data = new char[]{'h','e','l','l','o'};
String str = new String(data); //直接调用构造方法
System.out.println(str); //输出为hello
}
}
public String(char[] value,int offset,int count) 将部分字符数组转为字符串
//将部分字符数组转为字符串
public class Test6{
public static void main(String[] args){
char[] data = new char[]{'h','e','l','l','o'};
String str = new String(data,1,3); //直接调用构造方法,输出为ell
System.out.println(str);
}
}
6.2 将字符串转为单个字符
public char charAT(int index): 取得指定索引的字符
//将字符串转为单个字符
public class Test6{
public static void main(String[] args){
char c = "hello".charAt(1);
System.out.println(c); //输出为e
char d = "hello".charAt(1);
System.out.println(d+32); //输出为133
char e = "hello".charAt(7);
System.out.println(e); //编译不通过,字符数组
}
}
- 字节与字符串
7.1 将字节数组转为字符串
byte[] --> String
public String(byte[] value)
//判断一个字节是否是字符串
public class Test6{
public static void main(String[] args){
byte[] data = new byte[]{1,3,5,7,9};
String str = new String(data);
System.out.println(data);
}
}
7.2 将字符串转为字节数组
String --> byte[]
public byte[] getBytes();
//将字符串转为字符数组
public class Test6{
public static void main(String[] args){
String str = "hello";
byte[] data = str.getBytes();
System.out.println(data);
for(byte b : data){
System.out.println(b);
}
}
}
7.3 将字符串按照指定编码
public byte[] getBytes(String charsetName):
//将字符串按照指定编码转为字节数组
public class Test6{
public static void main(String[] args) throws Exception{ //抛出异常是因为以下那种编码格式会产生异常
String str = "hello";
byte[] data = str.getBytes("ISO-8859-1"); //一种编码格式
for(byte b : data){
System.out.println(b);
}
}
}
- 字符串比较
8.1 不区分大小写相等比较
public boolean epualsIgnoreCase(String anotherString)
public class Test6{
public static void main(String[] args){
System.out.println("hello".equalsIgnoreCase("HELLO"));
}
}
8.2比较两个字符串大小
public int compareTo(String anotherString)
1.返回大于0:表示大于比较对象
2.返回等于0:两者相等
3.返回小于0:表示小于比较对象
public class Test6{
public static void main(String[] args){
String str1 = "hello";
String str2 = "Hello"; //从第一个字符开始比较,若有差异则不再比较,且大小写敏感
System.out.println(str1.compareTo(str2)); //中文也可比较,有其内部编码规则
}
}
9.字符串查找(重要)
判断str在本字符串中是否存在:public boolean contains(String str)
//判断STR是否在本字符串中
public class Test6{
public static void main(String[] args){
String str1 = "he";
String str2 = "hello";
System.out.println(str2.contains(str1));
}
}
判断是否以指定字符串开头:public boolean startsWith(String str)
//判断是否以指定字符串开头
public class Test6{
public static void main(String[] args){
String str1 = "e";
String str2 = "hello";
System.out.println(str2.startsWith(str1)); //输出为false
}
}
从指定位置开始判断是否以指定字符串开头:public boolean startsWith(String str, int index)
//判断是否以指定字符串开头
public class Test6{
public static void main(String[] args) throws Exception{
String str1 = "e";
String str2 = "hello";
System.out.println(str2.startsWith(str1,1)); //输出为true
}
}
10.字符串替换
替换所有指定内容:public String replaceAll(String regex,String replacement)
//字符串替换
public class Test6{
public static void main(String[] args){
String str2 = "hello world!";
System.out.println(str2.replaceAll("l","_")); //前一个为要被替换的,后一位替换的
} //输出为he__o wor_d
}
替换首个内容:public String replaceFirst(String regex,String replacement)
//字符串替换
public class Test6{
public static void main(String[] args){
String str2 = "hello world!";
System.out.println(str2.replaceAll("l","_")); //前一个为要被替换的,后一位替换的
System.out.println(str2.replaceFirst("l","_")); //输出为he_lo world
}
}
11字符串拆分
将字符串按照指定格式全部拆分:public String[] split(String regex)
//字符串全部拆分
public class Test6{
public static void main(String[] args){
String str2 = "hello world hello java";
String[] result = str2.split(" ");
for(String str: result){
System.out.println(str);
}
}
}
将字符串拆分部分,数组长度为limit:public String[] split(String regex,int limit)
//字符串拆分
public class Test6{
public static void main(String[] args){
String str = "192.168.1.1";
String[] result = str.split("\\.");
for(String temp:result){
System.out.println(temp);
}
}
}
12字符串截取
public String substring(int beginIndex):从指定位置截取到字符串的结尾
public String substring(int beginIndex,int endIndex):截取部分内容
//字符串截取
public class Test6{
public static void main(String[] args){
String str = "helloworld";
String result = str.substring(5);
String re = str.substring(0,5); //左闭右开
System.out.println(result);
System.out.println(re);
}
}
13其他方法
13.1.去掉字符串左右的空格
public String trim();
public class Test6{
public static void main(String[] args){
String str = " hello world ";
String result = str.trim();
System.out.println(result);
}
}
13.2 字符串转大小写
public String toUpperCase();
public String toLowerCase();
public class Test6{
public static void main(String[] args){
String str = " hello world ";
System.out.println(" hello world ".toUpperCase()); //转大写
System.out.println(str.toLowerCase()); //转小写
}
}
13.2 判断字符串是否为空(只能判断是否为空字符串而不是Null)
public boolean isEmpty();
public class Test6{
public static void main(String[] args){
String str = "hello";
System.out.println(str.isEmpty());
}
}