【Java SE】String类(上)

简介: 在我们前面也对字符串进行了简单的使用,在Java当中,String是字符串类型,本质上也是一个类,这个类中提供了很多的方法,我们后续会学习到,现在先来简单看一下String类常见的构造方法

1、字符串的构造  

1.1 简单初始化字符串

在我们前面也对字符串进行了简单的使用,在Java当中,String是字符串类型,本质上也是一个类,这个类中提供了很多的方法,我们后续会学习到,现在先来简单看一下String类常见的构造方法:

public static void main(String[] args) {
        String str1 = "hello";
        String str2 = new String("hello");
        char[] array = { 'h','e','l','l','o' };
        String str3 = new String(array);
}

还有其他的构造方法,但是常用的就上面这三种,分别是使用常量字符串构造,也就是直接用一个常量字符串赋值给String类型的变量(引用),第二种就是new一个String的对象,第三种是将字符数通过String构造方法转换成字符串。

至于第一种和第二种写法有什么区别,等后面我们学了字符串常量池放在那个时候讲解。

1.2 String是引用类型

因为String是引用类型,所以内部并不存储字符串本身,在String内部原码中,String类实例变量如下:

通过查看String类的原码可以发现,其实一个String引用的对象里面是有两个实例变量的,分别是value 字符数组 和 hash 也就是哈希, 所以在JDK1.8中,字符串实际保存在char类型的数组里头,这里我们先来简单的看一段代码:

public static void main(String[] args) {
        // s1和s2引用的是不同对象 s1和s3引用的是同一对象
        String s1 = new String("hello");
        String s2 = new String("hello");
        String s3 = s1;
        System.out.println(s1 == s2); // false
        System.out.println(s1 == s3); // true
    }

为了方便大家更好的了解,我们给上面的代码画一个草图,并不是真正的内存布局图!但不影响我们的理解,等到字符串常量池会给大家画真实的内存布局:

所以上面的代码打印的结果也就是 fasle 和 ture,因为引用使用 == 比较比较的是存储的地址是否相同,而通过上图就能发现 s1 和 s3 存储的地址是相同的,所以打印结果正如我们猜想的一样:

这里我们还需要注意一点,使用 "" 引起来的也是String类型对象,也可也调用对象中可以调用的属性:

// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());

2、String类常用方法

2.1 String对象的比较方法

在Java中我们有四种的比较方法,当然对于初学者见过最多的就是 == 的比较,但是这个在引用类型比较的是引用的地址是否相同,而基本类型则是比较里面存储的值是否相同,简单来说就是比较变量存储的值,所以 == 号我们不做过多的阐述。

2.1.1 boolean equals(Object anObject) 方法

这个方法其实也不陌生,之前也见过,他是按照字典序也就是字符大小的顺序进行比较,而Sting类中重写了 equals 方法,具体我们可以看一下方法的实现:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        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;
    }

这个就是String类中重写 equals 方法的实现代码了,我们简单分析一下:

第一步:首先判断当前引用和 anObject也就是传过来的引用所引用的对象是否相同,因为Object是所有类的父类,这里用到了向上转型,如果引用的是同一个对象则返回 true

第二步:判断 anObject 里面的对象是不是 String 类型对象,如果是就继续比较,不是则直接返回false。

第三步:如果 anObject里面的对象是String类型对象,我们就先把anObject向下转型成String对象,这样就能访问本身对象自己的属性了,接着把当前对象里面字符数组的长度赋值给了n,在判断当前两个对象的里面存放的字符数组长度是否相同,相同则继续比较不是还是返回false。

第四步:如果if里面的字符长度相同,我们就按照字典序逐个字符往后比较,当这个if里面循环成功走完了,也就返回了true,一旦发现有一个字符不相同就会返回false

原码已经简单的分析过了,至于这个方法的使用前面也见到过,所以剩下使用就交给各位感兴趣的下来摸索了。

2.1.2 int compareTo(String s)方法

这个方法是实现的 Comparable 接口里面的 compareTo 方法,与上面不同的是,他返回的是int类型,并不是boolean类型,具体比较方式也是按照字典序进行比较,如果出现不同的字符,就直接返回这两个字符的差值,如果前 k 个字符(k为两个字符串最小的长度值),就返回两个字符串的差值。

public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

这个原码实现的也很简单我们上面也简单说明了一下,就不多说,感兴趣的还是要自己下来用一用这个方法。

2.1.3 int compareToIgnoreCase(String s)方法

这个方法跟上面的  compareTo 方法的区别就是忽略了大小写比较,这里如果要看原码已目前的知识储备是不好理解的,这个知道如何使用就行:

public class Main {
    public static void main(String[] args) {
        String s1 = "HeLLO";
        String s2 = "hEllo";
        System.out.println(s1.compareToIgnoreCase(s2));
    }
}

2.2 字符串查找方法

字符串查找是很常见的操作,在日常刷题的过程中也会碰到,而Java中用的比较多的就是 char charAte(int index) ,int indexOf(...),int lastIndexOf(...),里面打三个点是因为这些方法都被重载了,形参列表是不同的,具体看下面代码和注释:

public static void strFind() {
        String str = "hello";
        //返回字符串某个位置上的字符,不能越界也不能是负数
        System.out.println(str.charAt(1));
        //返回指定字符第一次出现的位置,没有返回-1
        System.out.println(str.indexOf('l'));
        //从fromIndex位置开始找指定字符第一次出现的位置,没有返回-1
        System.out.println(str.indexOf('l', 3));
        //返回一个字符串第一次出现的起始位置,没有返回-1
        System.out.println(str.indexOf("el"));
        //从fromIndex位置开始找指定字符串第一次出现的位置,没有返回-1
        System.out.println(str.indexOf("el", 2));
        //从后往前找,返回指定字符第一次出现的位置,没有返回-1
        System.out.println(str.lastIndexOf('e'));
        //从fromIndex位置从后往前找到指定字符第一次出现的位置,没有返回-1
        System.out.println(str.lastIndexOf('e', 3));
        //从后往前找指定字符串第一次出现的位置,没有返回-1
        System.out.println(str.lastIndexOf("el"));
        //从fromIndex位置从后往前找指定字符串第一次出现的位置,没有返回-1
        System.out.println(str.lastIndexOf("el", 4));
    }

这个比较简单,下来多练习下就好了,至于原码的实现不必太过关心,如果每个都去解读原码那得讲到后年马月, 感兴趣的可以下来自己看一看,按Ctrl+鼠标左键,点一下你要进入的方法名就好了。

注意:上面的方法都是要依赖于对象的,也就是实例方法。

2.3 转换相关的方法

2.3.1 数值和字符串之间的转换

public static void strTransform() {
        //数字转字符串
        String s1 = String.valueOf(123);
        String s2 = String.valueOf('b');
        String s3 = String.valueOf(12345f);
        String s4 = String.valueOf(true);
        String s5 = String.valueOf(new Student("张三", 24));
        //字符串转数字
        int a = Integer.parseInt("1234");
        double d = Double.parseDouble("123.4");
}

2.3.2 大小写转换

public static void strTransform() {
        //大小写转换
        String str1 = "hELlo";
        //转换会产生一个新的对象,不会修改原有的字符串
        System.out.println(str1.toUpperCase()); //小写转大写
        System.out.println(str1.toLowerCase()); //大写转小写
}

2.3.3 字符串转数组

public static void strTransform() {
        //字符串转数组
        String str2 = "hello";
        char[] array1 = str2.toCharArray(); //使用toCharArray方法
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + " ");
        }
        System.out.println();
        //数组转字符串
        char [] array2 = new char [] { 'a','b','c' };
        String str3 = new String(array2);
        System.out.println(str3);
}

2.3.4 格式化

public static void strTransform() {
        //格式化
        String str4 = String.format("%d-%d-%d", 2022, 8, 19);
        System.out.println(str4);

最终输出这个字符串也就是会打印:2022-8-19,学过C语言的小伙伴可能会比较的熟悉,这里照葫芦画瓢即可,得注意一个点,如果是特殊字符格式化比如 %d\%d\%d,这里我们要转义一下即可,如果不知道 %d 是什么意思,可以去参考下C语言的文章。

相关文章
|
5天前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
|
22天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
43 17
|
14天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
18天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
66 4
|
19天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
40 2
|
23天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
27天前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
|
27天前
|
Java API Maven
如何使用 Java 字节码工具检查类文件的完整性
本文介绍如何利用Java字节码工具来检测类文件的完整性和有效性,确保类文件未被篡改或损坏,适用于开发和维护阶段的代码质量控制。
|
27天前
|
存储 Java 编译器
java wrapper是什么类
【10月更文挑战第16天】
31 3
|
30天前
|
Java 程序员 测试技术
Java|让 JUnit4 测试类自动注入 logger 和被测 Service
本文介绍如何通过自定义 IDEA 的 JUnit4 Test Class 模板,实现生成测试类时自动注入 logger 和被测 Service。
23 5
下一篇
无影云桌面