String类

String类的创建

//方式一
String str = "hello word";
//方式二
String str = new String("hello word");
//方式三
char[] arr = {'a', 'b', 'c'};
String str = new String(arr);

我们看看以上代码的内存分布图:


引用类型有点类似c语言中的指针,我们在内存中开辟了一小块内存空间保存一个地址,但是与c语言不同的是指针能进行数字运算,但引用不行,java中String就是引用类型.
由于String是引用类型,因此我们分析以下代码的内存分布:

String str1 = "hello word';
String str2 = str1;
QQ截图20210128173143.png

修改str1的值,看看str2是否会随之改变

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = "hello word";
        String str2 = str1;
   
        str1 = "zmm";
        System.out.println(str2);
    }
}

image.png

从内存分布分析此结果

image.png

可以看出我们修改str1并不会影响str2的结果,也就意味着我们修改了str1其实只是修改了str1的指向,让str1引用指向了一个新的String对象

字符串比较相等

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = "hello";
        String str2 = "hello";
        System.out.println(str1 == str2);
    }
}
image.png

那么根据以上结果,是否就能确定判断字符串相等可以用 '' == '', 我们再看一个例子:

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = new String("hello");
        String str2 = new String("hello");
        System.out.println(str1 == str2);
    }
}
QQ截图20210128180011.png

我们分析两种创建String方式的差异
第一种:

QQ截图20210128173143.png

str1 和str2 是指向同一个对象,是由于像 " hello '' 这样的字符串,我们是将它保存在字符串常量池中的,如果我们需要使用 '' hello '' 这个字符串常量,就直接引用字符串常量池的这个位置就可.
第二种:
QQ截图20210128173143.png

用 String str1 = new String(" hello ") 这个方式创建对象,我们在内存中开了两块空间,来保存 " hello "这个字符串,因此在用" == " 比较两个字符串是否相等的时候,其实是在比较两个字符串的地址是否一样,而不是比较字符串的内容

equals方法来比较字符串内容是否相等

import java.util.Arrays;

public class test {
public static void main(String[] args) throws NameException, PasswordException {
        String str1 = new String("hello");
        String str2 = new String("hello");

        System.out.println(str1.equals(str2));
    }
}
QQ截图20210128180011.png

使用 equals 的注意事项

//方式一
System.out.println(" hello ".equals(str2));
//方式二
System.out.println(str1.equals(str2));

以上两种方式我们更推荐方式一,若一旦 " str1 = null "那么就会抛出异常
方式二

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = null;
        String str2 = new String("hello");

        System.out.println(str1.equals(str2));
    }
}
QQ截图20210128180011.png

方式一

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = null;
        String str2 = new String("hello");

        System.out.println("hello".equals(str1));
    }
}
QQ截图20210128180011.png

字符串常量池

直接赋值

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = "hello";
        String str2 = "hello";

        System.out.println(str1 == str2);
    }
}

在JVM底层实际上会自动维护一个对象池(字符串常量池)

  • 如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中.
  • 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接行引用
  • 如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用

采用构造方法

String str = new String(" hello ");

这样的做法有两个缺点:

  • 如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间(字符串常量 "hello" 也是一个匿名对象, 用了一次之后就不再使用了, 就成为垃圾空间, 会被 JVM 自动回收掉).
  • 字符串共享问题,同一个字符串可能被储存多次,比较浪费空间

intern 方法可以显示把对象入池

import java.util.Arrays;
//判断str是否入池
public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        
        String str1 = new String("hello");
        System.out.println(str1 == "hello");
    }
}
QQ截图20210128180011.png
import java.util.Arrays;

public class test {
    public static void main(String[] args) {
        //显示入池
        String str1 = new String("hello").intern();
        System.out.println(str1 == "hello");
    }
}
QQ截图20210128180011.png

结论

  • 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用
  • 构造方法:会开辟两块堆内存空间,不会自动保存在对象池中,可以使用intern()方法手工入池
  • 我们一般采用直接赋值的方式创建String类对象

字符串的不可变

字符串是一种不可变对象,它的内容不可变
String类的内部实现也是基于char[ ]来实现,但是String类并没有提供set方法来修改内部字符数组

public class example {
    public static void main(String[] args) {
       String str = "hello ";
       str = str + "word";
       str += "!!!";
        System.out.println(str);
    }
}
QQ截图20210128180011.png

内存分布图

QQ截图20210129170441.png

字符串str拼接以后,str的引用指向改变了,但String的对象并没有改变

String不可变的好处:

  • 方便实现字符串对象池
  • 不可变对象线程安全
  • 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中

字符、字节与字符串

方法名称 类型 描述
public String(char value[]) 构造 使用字符数组的内容构造一个字符串
public String(char value[],int offset, int court) 构造 使用字符数组中以offset下标开始的连续count个字符构造一个字符串
public char charAt(int index) 普通 获得字符串中指定索引的字符
public char[] toCharArray() 普通 将字符串变为字符数组返回
  • 示例代码1:字符数组转字符串
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        char[] arr = {'a','b','c'};
        String str = new String(arr);
        System.out.println(str);
    }
}
image.png
  • 示例代码2:将指定字符转成字符串
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        char[] arr = {'a','b','c','d','f'};
        String str = new String(arr,2,3);
        System.out.println(str);
    }
}
QQ截图20210128180011.png
  • 示例代码3:获得字符串中的某个字符
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str = "hello";
        char ch = str.charAt(4);
        System.out.println(ch);
    }
}
QQ截图20210128180011.png
  • 示例代码4:字符串转成字符数组
import java.util.Arrays;
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str = "hello";
        char[] str1 = str.toCharArray();
        System.out.println(Arrays.toString(str1));
    }
}
QQ截图20210128180011.png

字符串常见操作

字符串常见比较

方法名称 类型 描述
public boolean equals(Object anObject) 普通 区分大小写的比较
public boolean equalsIgnoreCase(String anotherString) 普通 不区分大小写的比较
public int compareTo(String anotherString) 普通 两个字符串比较关系
  • 示例代码1
import java.util.Arrays;
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "Hello";
        System.out.println(str1.equals(str2));
    }
}
image.png
  • 示例代码2:
import java.util.Arrays;
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "Hello";
        System.out.println(str1.equalsIgnoreCase(str2));

    }
}
image.png
  • 示例代码3:
import java.util.Arrays;
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "Hello";
        System.out.println(str1.compareTo(str2));

    }
}
image.png
public class example {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "hello";
        System.out.println(str1.compareTo(str2));

    }
}
image.png
public class example {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "Hello";
        System.out.println(str1.compareTo(str2));

    }
}
image.png

使用compareTo()这个方法,若两个字符串相等,则返回0;反之返回将字符串中的字符一一比较返回其差值;

不区分大小写的字符串比较

public class example {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "Hello";
        
        System.out.println(str1.equalsIgnoreCase(str2));

    }
}
image.png

字符串查找

所谓字符串查找就是从一个完整的字符串之中可以判断指定内容是否存在

方法名称 类型 描述
public boolean contains(CharSequence s) 普通 判断一个子字符串是否存在
public int indexOf(String str) 普通 从左开始向右查找指定字符串是否存在,查到了返回位置的开始索引,如果查不到返回-1
public int indexOf(String str, int fromIndex) 普通 从指定位置开始查找子串的位置
public int lastIndexOf(String str) 普通 由右向左查找子字符串位置
public int lastIndexOf(String str, int fromIndex) 普通 从指定位置由右向左查找子串
public boolean startsWith(String prefix) 普通 判断是否以指定字符串开头
public boolean startsWith(String prefix, int toffset) 普通 从指定位置开始判断是否以指定字符串开头
public boolean endsWith(String suffix) 普通 判断是否以指定字符串结尾
  • 示例代码1:
public class example {
    public static void main(String[] args) {
        String str1 = "Hello word";
        System.out.println(str1.contains("word"));

    }
}
image.png
  • 示例代码2:
public class example {
    public static void main(String[] args) {
        String str1 = "Hello word";
        String str2 = "word";
        System.out.println(str1.indexOf(str2));

    }
}
image.png
  • 示例代码3:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adcmfro";
        String str1 = "m";
        System.out.println(str.indexOf(str1, 3));
    }
}
QQ截图20210128180011.png
  • 示例代码4:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        String str1 = "r";
        System.out.println(str.lastIndexOf(str1));
    }
}
image.png
  • 示例代码5:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        String str1 = "r";
        System.out.println(str.lastIndexOf(str1, 4));
    }
}
image.png
  • 示例代码6:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        System.out.println(str.startsWith("amm"));
    }
}
image.png
  • 示例代码7:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        System.out.println(str.startsWith("ad",0));
    }
}
image.png
  • 示例代码8:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        System.out.println(str.endsWith("r"));
    }
}
image.png

字符串替换

使用一个指定的新的字符串替换掉已有的字符串数据,可用方法如下

方法名称 类型 描述
public String replaceAll(String regex, String replacement) 普通 替换所有的指定内容
public String replaceFirst(String regex, String replacement) 普通 替换首个内容
  • 示例代码:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "helloword";
        System.out.println(str.replaceAll("l", "m"));
        System.out.println(str.replaceFirst("l", "x"));
        System.out.println(str.replace("w", "o"));
    }
}
image.png

注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串.

字符串拆分

可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串

方法名称 类型 描述
public String[] split(String regex) 普通 将字符串全部拆分
public String[] split(String regex, int limit) 普通 将字符串部分拆分,该数组的长度极限就是limit
  • 示例代码1:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "hello word";
        String[] s = str.split(" ");
        for(String x: s) {
            System.out.println(x);
        }
    }
}
image.png
  • 示例代码2:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "hello word hello zmm";
        String[] s = str.split(" ", 2);
        for(String x: s) {
            System.out.println(x);
        }
    }
}
image.png
  • 示例代码3:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "192.168.1.1";
        String[] s = str.split("\\.");
        for(String x: s) {
            System.out.println(x);
        }
    }
}
image.png

注意事项:

  • 字符"|","*","+"都得加上转义字符,前面加上" \ "即可.
  • 而如果是"",那么就得写成"\".
  • 如果一个字符串中有多个分隔符,则可以用" | "作为连接符

字符串截取

从一个完整字符串之中截取部分内容,可用方法如下

方法名称 类型 描述
public String substring(int beginIndex) 普通 从指定索引截取到结尾
public String substring(int beginIndex, int endIndex) 普通 截取部分内容
  • 示例代码1:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "helloword";
        System.out.println(str.substring(4));
    }
}
image.png
  • 示例代码2:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "helloword";
        System.out.println(str.substring(4, 6));
    }
}
image.png

注意事项:

  • 索引从0开始
  • 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标

其他操作方法

方法名称 类型 描述
public String trim() 普通 去掉字符串中的左右空格,保留中间空格
public String toUpperCase() 普通 字符串转大写
public String toLowerCase() 普通 字符串转小写
public native String intern() 普通 字符串入池操作
public String concat(String str) 普通 字符串连接,等同于"+",不入池
public int length() 普通 取得字符串长度
public boolean isEmpty() 普通 判断字符串是否为空(不是null,而是长度为0)
  • 示例代码1:
package xsk;

public class Test {
    public static void main(String[] args) {
      String str = " hello bit hello  ";
        System.out.println(str.trim());
    }
}
image.png
  • 示例代码2:
package xsk;

public class Test {
    public static void main(String[] args) {
      String str = " Hello bit hello  ";
        System.out.println(str.toUpperCase());
    }
}
image.png
  • 示例代码3:
package xsk;

public class Test {
    public static void main(String[] args) {
      String str = " Hello bit hello  ";
        System.out.println(str.toLowerCase());
    }
}
image.png
  • 示例代码4:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = " Hello bit hello ";
        String str1 = "aaa";
        System.out.println(str.concat(str1));
    }
}
image.png
  • 示例代码5:

public class Test {
    public static void main(String[] args) {
        String str = " Hello bit hello ";

        System.out.println(str.isEmpty());
        System.out.println(str.length());
    }
}
image.png

String Buffer 和 String Builder

StringBuffer和StringBuilder是为了解决String是不可变对象带来的麻烦
我们来看一下之前那个频繁拼接字符串的代码

public class Test {
    public static void main(String[] args) {
        String str = "hooo";
        for(int i = 0; i < 10; i++) {
            str += i;
        }
        System.out.println(str);

    }
}
image.png

我们知道String是不可变对象,所以这个代码的效率很低,就是在频繁的创建新的对象。我们使用StringBuffer和StringBuilder来分别优化一下这个代码

public class Test {
    public static void main(String[] args) {
        StringBuffer str = new StringBuffer("hoooo");
        for(int i = 0; i < 10; i++) {
            str.append(i);
        }
        System.out.println(str);

    }
}
image.png

String、StringBuffer和StringBuilder的区别

  • String是不可变的,StringBuffer和StringBuilder都是可变的
  • StringBuffer和StringBuilder大部分功能都是类似的
  • StringBuffer采用同步处理,属于线程安全;StringBuilder没有采用同步操作,线程不安全
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容