【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语言的文章。

相关文章
|
6天前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
17 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
1天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
14 6
|
3天前
|
IDE Java 编译器
Java:如何确定编译和运行时类路径是否一致
类路径(Classpath)是JVM用于查找类文件的路径列表,对编译和运行Java程序至关重要。编译时通过`javac -classpath`指定,运行时通过`java -classpath`指定。IDE如Eclipse和IntelliJ IDEA也提供界面管理类路径。确保编译和运行时类路径一致,特别是外部库和项目内部类的路径设置。
|
2天前
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
10 2
|
3天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其独特的“不重复性”要求,彻底改变了处理唯一性约束数据的方式。
【10月更文挑战第14天】从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其独特的“不重复性”要求,彻底改变了处理唯一性约束数据的方式。本文深入探讨Set的核心理念,并通过示例代码展示了HashSet和TreeSet的特点和应用场景。
9 2
|
3天前
|
存储 Java 索引
Java 中集合框架的常见接口和类
【10月更文挑战第13天】这些只是集合框架中的一部分常见接口和类,还有其他一些如 Queue、Deque 等接口以及相关的实现类。理解和掌握这些集合的特点和用法对于高效编程非常重要。
|
5天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
10 1
|
8天前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
25 4
|
1月前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
34 0
java基础(13)String类
|
29天前
|
安全 Java
String类-知识回顾①
这篇文章回顾了Java中String类的相关知识点,包括`==`操作符和`equals()`方法的区别、String类对象的不可变性及其好处、String常量池的概念,以及String对象的加法操作。文章通过代码示例详细解释了这些概念,并探讨了使用String常量池时的一些行为。
String类-知识回顾①