数据结构中定义字符串是由零个或多个字符组成的有限序列,有限,指出字符串的长度是一个有限的数值;所谓的序列,说明串的相邻字符之间具有前驱和后继的关系。字符串一般记为s="a1a2...an"(n>=0),其中s是字符串的名称,用双引号括起来的字符序列是串的值,注意引号不属于串的内容。字符ai可以由字母,数字或其他字符组成,i(1≤i≤n)就是该字符在串中的位置。

在Java语言中将字符串作为对象来处理,可以通过访问Java API帮助文档java.lang包下的String类来看看字符串的相关方法。

首先看看String继承的超类和实现的接口有哪些?

1.字符串的常用方法

1.1 常用的构造方法底层实现

//1.由字符串original复制得到新的字符串
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
//2.得到值等于value的字符串
public String(char[] value) {
this.value = Arrays.copyOf(value, value.length);
}
//3.返回字符串从第i个位置起的前j个字符
public String(char[] value, int offset, int count) {
    //判断索引i是否合法
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    //判断计数值是否合法
    if (count <= 0) {
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        //如果计数值等于0,返回的是空字符
        if (offset <= value.length) {
            this.value = "".value;
            return;
        }
    }
    //索引值>字符串长度-计数值,抛异常
    if (offset > value.length - count) {
        throw new StringIndexOutOfBoundsException(offset + count);
    }
    //其余情况返回要求值
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}

1.2 equals方法

String中的equals()方法用来判断字符串的内容是否相等。String类中的equals方法是对父类Object类中的equals方法的覆盖,先来看下Object类的equals方法怎么写的:

public boolean equals(Object obj) {
return (this == obj);
}

这里的this哪个对象调用该方法,this就指代哪个对象。

String中的equals()方法底层源码:

public boolean equals(Object anObject) {
//调用该方法的对象与比较的参数相等,则返回true
if (this == anObject) {
return true;
}
//instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
//首先比较两个字符串实例长度是否相等
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
//比较两个字符串对应位置的字符是否相等
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

也就是说,使用equals()方法是用来比较两个字符串的内容是否相等,它通过以下方法实现:

  • 首先判断两个字符串实例是否是同一个对象,如果是,那么它们的内容相等,返回true;
  • 如果不是同一个对象,判断该对象是否是String类的实例,如果是,将该对象实例强转为String类,判断二者的长度是否相等;
  • 若满足长度相等,再一一比较两个字符串对应位置的字符是否相等;

提到equals方法,就得结合“==”操作符来看了。“==”操作符用来比较操作数的值之间的关系,对于基本数据类型,变量存储的是值本身,而对于引用数据类型,变量存储的是对象的地址,比较的是两个对象的内存地址是否相等。

String类代表字符串,Java程序中的所有字符串文字比如“abc”都被实现为此类的实例。字符串一经创建后,它的值是不可以改变的,也就是说“abc”不可以再变成“abcd”。这就要求我们使用String的时候应该注意:尽量不要做字符串频繁的拼接操作。因为字符串一旦创建不可改变,只要频繁拼接,就会在字符串常量池中创建大量的字符串对象,给垃圾回收带来问题。

为了提升字符串的访问效率,在程序中使用了缓冲技术,所有被双引号括起来的字符串都会在JVM运行时数据区的字符串常量池中新建一份,(字符串常量池存储在方法区中)。如果程序中用到“abc”,会先在字符串常量池中查找有没有该字符串,如果找到直接拿来用,找不到就在字符串常量池中新建一个"abc"。

如下的代码,判断两个字符串是否相等:

String A="a";
String B="a";
System.out.println(A==B); //true

前面提到过“==”是用来比较值相等。程序中第一次出现"a"时,先在字符串常量池中新建一个字符串"a"对象,A指向该对象,当程序中再次出现"a"时,会先在字符串常量池中查找,发现已经创建了"a",于是直接拿来用了,使用B指向,也就是A,B引用指向的是同一对象,所以打印输出true。

再来看看String中的构造方法:

这个方法是初始化新创建的String对象,使其表示与参数相同的字符序列,换句话说,新创建的字符串时参数字符串的副本。

看下面代码,判断是否相等:
String C=new String("a");
String D=new String("a");
System.out.println(C==D); //false

参数字符串“a”对象,创建之前先在字符串常量池中查找有没有该对象,没有则创建;然后构造方法String(String original)以"a"为参数,new出两个对象存在堆中,C和D引用分别指向这两个对象,很明显C和D引用指向的是两个不同的对象,即上面这两行代码创建了三个不同的对象,方法区中一个,堆中两个。

2.字符串的模式匹配

子串在主串中的定位操作称为串的模式匹配,串的模式匹配应该算串的重要操作之一。来看看朴素的模式匹配算法。

根据要求从主串的第i个位置开始遍历。子串从第0个位置开始,如果相应位置的字符相等,则主串子串各向后移动一位判断下一位字符,如果不等,主串回到匹配位置的下一位,子串从0位开始,循环遍历,直到找到子串,最后返回子串在主串中的索引。简单地说,就是对主串的每一个字符作为子串开头,与要匹配的字符串进行匹配,这种匹配方式称为朴素的模式匹配算法。实现代码如下:

package com.java.String;
/*
* 串的模式匹配
* */
public class IndexTest {
public static void main(String[] args){
int s=indexSearch("eateqweapple","app",8);
System.out.println(s);
}
//朴素的模式匹配算法,返回子串T在主串S中第pos个字符之后的位置
public static int indexSearch(String S,String T,int pos){
//默认值规定为0
int index=0;
int Slen=S.length();
int Tlen=T.length();
//S位置下标
int i=pos;
//T位置下标
int j=0;
while((i<Slen)&&(j<Tlen)){
char s=S.charAt(i);
char t=T.charAt(j);
if(s==t){
//如果当前位置的相等,都各加1比较下一位置
i=i+1;
j=j+1;
}else{
//否则回到主串S匹配的下一位置,子串从头开始
i=i+1;
j=0;
}
if(j>Tlen-1){
index=i-Tlen;
}
}
return index;
}
}

算法复杂度分析:

最好的情况,一开始就匹配成功,算法复杂度为O(1); 稍微差一些,每次匹配都是首字母不匹配,但遍历到主串的最后位置匹配成功,算法复杂度为O(n+m);最坏的情况,每次匹配不成功都是发生在子串的最后一个字符,时间复杂度为O((n-m+1)*m)。

朴素的模式匹配算法算很简单的解决子串定位问题的算法了。想一想Java底层那些封装好的方法,我们真是站在了巨人的肩膀上。

结合数据结构来看看Java的String类的更多相关文章

  1. java中String类为什么不可变?

    在面试中经常遇到这样的问题:1.什么是不可变对象.不可变对象有什么好处.在什么情景下使用它,或者更具体一点,java的String类为什么要设置成不可变类型? 1.不可变对象,顾名思义就是创建后的对象 ...

  2. 在java中String类为什么要设计成final?

    大神链接:在java中String类为什么要设计成final? - 程序员 - 知乎 我进行了重新排版,并且更换了其中的一个例子,让我们更好理解. String很多实用的特性,比如说“不可变性”,是工 ...

  3. Java的string类为什么是不可变的

    最流行的Java面试题之一就是:什么是不可变对象(immutable object),不可变对象有什么好处,在什么情况下应该用,或者更具体一些,Java的String类为什么要设成immutable类 ...

  4. Java中String类的方法及说明

    String : 字符串类型 一.      String sc_sub = new String(c,3,2);    //      String sb_copy = new String(sb) ...

  5. java.lang.String 类的所有方法

    java.lang.String 类的所有方法 方法摘要 char charAt(int index) 返回指定索引处的 char 值. int codePointAt(int index) 返回指定 ...

  6. java中String类学习

    java中String类的相关操作如下: (1)初始化:例如,String s = “abc”; (2)length:返回字符串的长度. (3)charAT:字符操作,按照索引值获得字符串中的指定字符 ...

  7. 深入分析Java的String类的方法与特点

    字符串是任何编程语言都必须支持的变量类型,有些编程语言是直接提供了原生的变量类型,有些编程语言则使用语法特性以 SDK 的形式提供支持.在Java编程平台中,对字符串的支持使用了后者的形式,就是通过在 ...

  8. java 中String类的常用方法总结,带你玩转String类。

    String类: String类在java.lang包中,java使用String类创建一个字符串变量,字符串变量属于对象.String类对象创建后不能修改,StringBuffer & St ...

  9. 在java中String类为什么要设计成final

    在java中String类为什么要设计成final? - 胖胖的回答 - 知乎 https://www.zhihu.com/question/31345592/answer/114126087

随机推荐

  1. .NET--------未能加载文件或程序集“System.Net.Http.Formatting”或它的某一个依赖项。

    未能加载文件或程序集“System.Net.Http.Formatting”或它的某一个依赖项.找到的程序集清单定义与程序集引用不匹配. (异常来自 HRESULT:0x80131040)   解决方 ...

  2. “ORA-12154: TNS: 无法解析指定的连接标识符”错误解决办法

    某政府项目中用.Net网站连接Oracle数据库,web.config使用的连接字符串如下: <add key="connstring_ora" value="Us ...

  3. SpringCloud系列------Config-Server

    关于Config-Server的那些事&踩过的坑! 一.概述 在一个相对成熟,高可用的Spring cloud项目中,都会配置一个配置中心去管理各个服务的配置文件,而往往配置文件不会放到本地配 ...

  4. Oracle学习DaySix(PL/SQL续)

    一.游标 在 PL/SQL 程序中,对于处理多行记录的事务经常使用游标来实现.游标是一个指向上下文的句柄( handle)或指针.通过游标,PL/SQL 可以控制上下文区和处理语句时上 下文区会发生些 ...

  5. 上传文件的三种方式xhr,ajax和iframe及上传预览

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. python实现文件的复制

      # 练习: # 1. 写程序,实现文件的复制,(注:只复制文件,不复制文件夹) # 要求: # 1) 要考虑文件关闭的问题 # 2) 要考虑超大文件无法一下加载到内存的问题 # 3) 要能复制二进 ...

  7. Groovy学习笔记-陷阱

    1.def和in是关键字 2.==映射到了equals() 中,如果有Comparable接口实现,则优先compareTo str1 = 'hello' str2 = str1 str3 = new ...

  8. windows7安装dlib过程中遇到的问题总结以及运行实例效果

    综合了无数网上记录过这个问题的文章,最后终于安装成功了! 首先有些文章说dlib从19.9版本起开始就不用cmake和boost的支持了,可能是我安装的dlib版本的问题?最后还是通过vs2015 + ...

  9. 监控网络带宽 使用speedtest-cli命令

    1.监控网络带宽 使用speedtest-cli命令 l 安装命令: yum install python-pip –y pip install speedtest-cli l 运行命令: speed ...

  10. java web从入门到精通

    1.Springboot配置 1.1mybatis mapper.xml所在的目录必须为resource的资源文件夹,如果xml文件在java的package里面,需要修改文件夹类型 idea修改方式 ...