JAVA学习笔记Ⅷ——JAVA中的字符串

什么是JAVA中的字符串

在程序开发中字符串无处不在,如用户登陆时输入的用户名、密码等使用的就是字符串。例如我们在控制台中输出的 “Hello World” 、 "你好世界"等。在 Java 中,字符串被作为 String 类型的对象处理。 String 类位于 java.lang 包中。默认情况下,该包被自动导入所有的程序。具体的实现方式见如下示例程序。
template23.java

package com;

public class template23 {
    public static void main(String[] args) {
        String myName1 = "郭权浩";
        String myBlank1 = "";

        //也可以使用new String()创建字符串以及空字符串
        String myName2 = new String("郭权浩");
        String myBlank2 = new String();

        System.out.println(myName1);
        System.out.println(myBlank1);

        System.out.println(myName2);
        System.out.println(myBlank2);
    }
}
郭权浩

郭权浩

JAVA字符串的不变性

String 对象创建后则不能被修改,是不可变的,所谓的修改其实是创建了新的对象,所指向的内存空间不同。

package com;

public class template23 {
    public static void main(String[] args) {
        String s1 = "imooc";
        String s2 = "imooc";

        //定义字符串s3,保存“I love”和s1拼接后的内容
        String s3 = "I love " + s1 ;

        // 比较字符串s1和s2
        // imooc为常量字符串,多次出现时会被编译器优化,只创建一个对象
        System.out.println("s1和s2内存地址相同吗?" + (s1 == s2));

        //比较字符串s1和s3
        System.out.println("s1和s3内存地址相同吗?" + (s1 == s3) );

        String s4 = "I love " + s1;
        //比较字符串s4和s3
        // s1是变量,s4在运行时才知道具体值,所以s3和s4是不同的对象
        System.out.println("s3和s4内存地址相同吗?" + (s4 == s3));
		s1 += " good platform";
    }
}

s1和s2内存地址相同吗?true
s1和s3内存地址相同吗?false
s3和s4内存地址相同吗?false

注意:imooc为常量字符串,多次出现时会被编译器优化,只创建一个对象,s1是变量,s4在运行时才知道具体值,所以s3和s4是不同的对象

通过 String s1="imooc"; 声明了一个字符串对象, s1存放了到字符串对象的引用,在内存中的存放引用关系如下图所示:

然后通过s1 += " good platform";改变了字符串 s1 ,其实质是创建了新的字符串对象,变量s1 指向了新创建的字符串对象,如下图所示:

一旦一个字符串在内存中创建,则这个字符串将不可改变。如果需要一个可以改变的字符串,我们可以使用StringBuffer或者StringBuilder

每次 new 一个字符串就是产生一个新的对象,即便两个字符串的内容相同,使用 ”==” 比较时也为 false ,如果只需比较内容是否相同,应使用 equals() 方法

String类常用方法

方法 说明
int length() 返回当前字符串的长度
int indexOf(int ch) 查找ch字符在该字符串中第一次出现的位置
int indexOf(String str) 查找str字符串在该字符串中第一次出现的位置
int lastIndexOf(int ch) 查找ch字符在该字符串中最后一次出现的位置
int lastIndexOf(String str) 查找str字符串在该字符串中最后一次出现的位置
String substring(int beginIndex) 获取从beginIndex位置开始到结束的子字符串
String substring(int beginIndex, int endIndex) 获取从beginIndex位置到endIndex位置的子字符串
String trim() 返回去除了前后空格的字符串
boolean equals(Object obj) 将该字符串与指定对象比较,返回true或false
String toLowerCase() 将字符串转换为小写
String toUppercase() 将字符串转换为大写
char charAt(int index) 获取字符串中指定位置的字符
String[] split(String regex, int limit) 将字符串分割为子字符串,返回字符串数组
byte[] getBytes() 将该字符串转换为byte数组
  1. 字符串 str 中字符的索引从0开始,范围为 0 到 str.length()-1

  2. 使用 indexOf 进行字符或字符串查找时,如果匹配返回位置索引;如果没有匹配结果,返回 -1

  3. 使用 substring(beginIndex , endIndex) 进行字符串截取时,包括 beginIndex 位置的字符,不包括 endIndex 位置的字符

程序要求:判断 Java 文件名是否正确,判断邮箱格式是否正确。其中:合法的文件名应该以 .java 结尾;合法的邮箱名中至少要包含 “@” , 并要求 “@” 在 “.” 之前
HelloWorld.java

public class HelloWorld {
    public static void main(String[] args) {
        // Java文件名
		String fileName = "HelloWorld.java"; 
        // 邮箱
		String email = "[email protected]";
		
		// 判断.java文件名是否正确:合法的文件名应该以.java结尾
        /*
        参考步骤:
        1、获取文件名中最后一次出现"."号的位置16.19.22.36
        2、根据"."号的位置,获取文件的后缀
        3、判断"."号位置及文件后缀名
        */
        //获取文件名中最后一次出现"."号的位置
		int index = fileName.lastIndexOf(".");
        
        // 获取文件的后缀
		String prefix = fileName.substring(index);
        
		// 判断必须包含"."号,且不能出现在首位,同时后缀名为"java"
		if ((index!=-1)&&(prefix.equals(".java"))) {
			System.out.println("Java文件名正确");
		} else {
			System.out.println("Java文件名无效");
		}

        // 判断邮箱格式是否正确:合法的邮箱名中至少要包含"@", 并且"@"是在"."之前
         /*
        参考步骤:
        1、获取文件名中"@"符号的位置
        2、获取邮箱中"."号的位置
        3、判断必须包含"@"符号,且"@"必须在"."之前
        */
	    // 获取邮箱中"@"符号的位置
		int index2 = email.lastIndexOf("@");
        
        // 获取邮箱中"."号的位置
		int index3 = email.indexOf('.');
        
		// 判断必须包含"@"符号,且"@"必须在"."之前
		if (index2 != -1 && index3 > index2) {
			System.out.println("邮箱格式正确");
		} else {
			System.out.println("邮箱格式无效");
		}
	}
}
Java文件名正确
邮箱格式正确

JAVA中 StringBuilder 与 StringBuffer

String 类具有是不可变性。如下代码所示

public class template23 {
    public static void main(String[] args) {
	String str = "hello";
	System.out.println(str + "world");
	System.out.println(str);
	}
}
helloworld
hello

从运行结果中我们可以看到,程序运行时会额外创建一个对象,保存 “helloworld”。当频繁操作字符串时,就会额外产生很多临时变量。使用 StringBuilder 或 StringBuffer 就可以避免这个问题

定义StringBuilder 类的对象如下

public class template23 {
    public static void main(String[] args) {
		StringBuilder str1 = new StringBuilder();
		StringBuilder str2 = new StringBuilder("imooc");
		System.out.print(str2);
	}
}
imooc

StringBuilder 类中的方法

方法 说明
StringBuilder append(参数) 追加内容到当前StringBuilder对象末尾
StringBuilder insert(位置, 参数) 将内容插入到StringBuilder对象的指定位置
String toString() 将StringBuilder对象转换为String对象
int length() 获取字符串的长度

例如如下代码中,创建了StringBuilder对象,用来存储字符串,并对其做了追加和插入操作。这些操作修改了str对象的值,而没有创建新的对象。

HelloWorld.java

public class HelloWorld {
    public static void main(String[] args) {
		// 创建一个空的StringBuilder对象
		StringBuilder str = new StringBuilder();
        
		// 追加字符串
		str.append("jaewkjldfxmopzdm");
		int a = str.length();
        // 从后往前每隔三位插入逗号
		while (a >= 3){
		    a -= 3;
		    str.insert(a,",");
		}
        
        // 将StringBuilder对象转换为String对象并输出
		System.out.print(str.toString());
	}
}
j,aew,kjl,dfx,mop,zdm

equals() 和 “==” 的区别

JAVA学习笔记Ⅲ——面向对象三特性之继承中有谈到equals()方法,其中描述是比较对象的引用是否指向同一块内存地址

我们先运行如下程序

public class template23 {
    public static void main(String[] args) {
        String myName1 = "郭权浩";
        String myName2 = "郭权浩";

        String myName3 = new String("郭权浩");
        String myName4 = new String("郭权浩");

        System.out.println("myName1是否equals myName2 " + myName1.equals(myName2));
        System.out.println("myName3是否equals myName4 " + myName3.equals(myName4));
        System.out.println("myName2是否equals myName4 " + myName2.equals(myName4));
        System.out.println("myName1是否== myName2 " + (myName1 == myName2));
        System.out.println("myName3是否== myName4 " + (myName3 == myName4));
        System.out.println("myName1是否== myName3 " + (myName1 == myName3));
        }
}
myName1是否equals myName2 true
myName3是否equals myName4 true
myName2是否equals myName4 true
myName1是否== myName2 true
myName3是否== myName4 false
myName1是否== myName3 false

其中有以下几个问题:
1.由于equals()是比较对象的引用是否指向同一块内存地址,那么理论上myName1=myName2≠myName3,因为新new出来的对象与原始定义的地址应该不同。
2.反观==,其中只有myName1myName2相同,因此,实际上==才是比较的地址,而equals()则是判断的字符串的内容。

对于==,我们可以理解,但是对于equals(),确实与我们的预期不相符合。

equals()方法介绍

JAVA当中所有的类都是继承于Object这个超类的,在Object类中定义了一个equals的方法,equals的源码是这样写的:

Object.java

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

而在String类中,此方法被重写了,如下所示:

String.java

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (coder() == aString.coder()) {
                return isLatin1() ? StringLatin1.equals(value, aString.value)
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }

因此,可以看到,这个方法的初始默认行为是比较对象的内存地址值,一般来说,意义不大。所以,在一些类库当中这个方法被重写了如String、Integer、Date在这些类当中equals有其自身的实现(一般都是用来比较对象的成员变量值是否相同),而不再是比较类在堆内存中的存放地址了。
所以说,对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是内存中的存放位置的地址值,跟双等号(==)的结果相同;如果被复写,按照复写的要求来。

综上:
==: 判断两个字符串在内存中首地址是否相同,即判断是否是同一个字符串对象
在String类中,equals()比较存储在两个字符串对象中的内容是否一致

附:JAVA源码查看

如何查看JAVA源码,查看JAVA源码需要编译器进行查看,对于安装路径的JAVA,例如以我安装的JAVA-11版本为例,在E:\Java\jdk-11.0.7\legal有大量的包,但在每一个包下,只有.md文件即markdown文件,因此只有在编译器中打开,例如intelliJ中。

猜你喜欢

转载自blog.csdn.net/qq_39567427/article/details/107503882
今日推荐