理解String 类(上)

简介: 理解String 类(上)

引言



我们都知道在C语言中是没有字符串类型的,C语言中,最常用的就是将字符串放进一个数组中,之后,对数组进行一些操作。而在 Java / C++ 中,有直接表示字符串的类型。在Java 中,String 类型就是表示字符串类型,同时它也是引用类型。比方说:


String str = "abcd";


没错,在 Java 中,字符串就是上述这样定义并初始化的,而 abcd 的末尾没有像 C语言那样有 \0,在 Java 中,里面就是 abcd.

在上面的一行代码中,被双引号引起来的 abcd 就叫做字符串,它是有a、b、c、d 这四个字符组成的,而 abcd 又属于字面值常量,其本质是常量,不可以被更改。


一、创建字符串的方式



1. 直接赋值


程序清单1:


public class Test1 {
    public static void main(String[] args) {
        String str1 = "hello";
    System.out.println(str1); 
    //输出结果:hello        
    }
}


2. 通过使用构造方法


程序清单2:


public class Test2 {
    public static void main(String[] args) {
        String str2 = new String("world");
        System.out.println(str2); 
        //输出结果:world
    }
}


3. 通过使用字符数组转换成字符串


程序清单3:


public class Test3 {
    public static void main(String[] args) {
        char[] chars = {'x','y','z'};
        String str3 = new String(chars);      
        System.out.println(str3); 
        //输出结果:xyz
    }
}


二、字符串的引用变量比较相等



1. 情况一


在程序清单4中,例如(str1 == str2)的这种形式,比较的其实是两个引用的地址,而不是字符串的内容 " hello ",这点需要理解,请往下看:


程序清单4:


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


输出结果:


d15961f5dd734f6db8c380290533829f.png


图解上述代码:


165b643e8c9c411e967e3bba437e0a55.png


String 类的设计使用了共享设计模式:

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

如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用。


2. 情况二


程序清单5:


public class Test5 {
    public static void main(String[] args) {
        String str1 = new String("hello");
        String str2 = new String("hello");
        System.out.println(str1 == str2);
    }
}


输出结果:


6abd8debd8bd4f18b99e6a2bcd8b5297.png


图解上述代码:


3d1133069c7b47838d7c78399e0ba2dc.png


3. 情况三


程序清单6:


public class Test6 {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = new String("hello");
        System.out.println(str1 == str2);
    }
}


输出结果:


c108169bbe1e405aa566f787805fa5d3.png


图解上述代码:


556cf9df5ac741f5bfda60e4e538f385.png


总结:


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


总结:


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


字符串常量池:主要存放字符串常量,本质上是一个哈希表,StringTable,双引号引起来的字符串常量。


三、理解字符串不可变



String 类的内部实现是基于 char[ ] 来实现的,但是 String 类并没有提供 set 方法之类的来修改内部的字符数组。


程序清单7:


public class Test7 {
    public static void main(String[] args) {
        String str1 = "abc";
        System.out.println(str1);
        str1 = "xyz";
        System.out.println(str1);
    }
}


输出结果:


942dc1e0368f4f8fa0635657c80d61a9.png


注意:在这里,我们并不是通过把字符串的内容修改了,而是将 [ str1 引用 ] 引用了新的对象。


40d7719a6a6645228c39768e1eb3c7df.png


程序清单8:


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


输出结果:


8870f8b48199492c9b90fbb9697d406b.png


同样地,在程序清单8中,我们并不是将 " hello " 中的内容修改了,而是先通过 " hello " 和 " world " 创建了一个新的对象 " hello world ",之后又通过 " hello world " 和 " !!! " 创建了另一个新的对象 “hello world !!!”。对于这样的操作,相当于每次都要通过关键字 new 实例化一个对象。所以,程序清单8是一个不好的示范,对于程序员来说,不应该这么做。


四、字符、字节、字符串、数组



1. 将字符数组转换成字符串


程序清单9:


public class Test9 {
    public static void main(String[] args) {
        char[] chars = {'a','b','c','d'};
        String str = new String(chars);
        System.out.println(str);
    }
}
//输出结果:abcd


2. 拿到字符串中的连续字符


程序清单10:


public class Test10 {
    public static void main(String[] args) {
        char[] chars = {'a','b','c','d'};
        String str = new String(chars, 1, 2);
        System.out.println(str);
    }
}
//输出结果:bc


String str1 = new String(char[] chars,int offset, int count);

在 String 构造方法中,其中 offset 表示偏移量,count 表示偏移个数,若 offset 为 1,count 为 2,那么,实现 str1 就从数组下标1开始,往后拿2个元素。当然,我们应该注意不能越界哦。


3. charAt( ) 方法 [ 常用 ]


程序清单11:


public class Test11 {
    public static void main(String[] args) {
        String str = "abcde";
        char ch = str.charAt(2);
        System.out.println(ch);
    }
}
//输出结果:c


harAt(int index)


index 表示指定位置的索引,字符串第一个字符索引为 0。

同样地,我们应该注意不能越界哦。


4. 将字符串转变成字符数组 [ 常用 ]


程序清单12:


public class Test12 {
    public static void main(String[] args) {
        String str = "abcde";
        char[] chars = str.toCharArray();
        System.out.println(Arrays.toString(chars));
    }
}
//输出结果:[a, b, c, d, e]


上面四个程序清单说明的是字符数组与字符串之间的一些操作,如果把字符数组换成字节数组,整型数组等等…其对应的思想是一样的。感兴趣的小伙伴可以自己试一下字节与字符串之间的关系。


5. 判断字符串是是由字符构成还是由数字构成


判断一个字符串是否是由字符构成

思路:我们创建一个 judge( ) 方法来判定每个字符是否由字母组成即可,所以我们遍历整个字符串的长度,然后通过下面两行代码来验证每一个字符:


char ch = str.charAt(i);
boolean sign = Character.isLetter(ch);


程序清单13:


public class Test13 {
    public static boolean judge(String str){
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            boolean sign = Character.isLetter(ch);
            if(sign == false){
                return false;
            }
        }
        return true;
    }
    public static void main(String[] args) {
        String str = "abcde";
        System.out.println(judge(str));
    }
}
//输出结果:true


当然,我们也可以判定是否每个字符是数字,只不过逻辑需要改变一下,代码如下:


char ch = str.charAt(i);
boolean sign = Character.isDigit(ch);


五、字符串比较



1. equals( ) 方法


查看底层代码,通过 equals( ) 方法比较字符串的内容,返回类型是布尔类型。


36962c3fe99c4cb69e9a5eaec1022015.png


程序清单14:


public class Test14 {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = new String("hello");
        System.out.println(str1.equals(str2));
        String str3 = null;
        String str4 = "hello";
        //System.out.println(str3.equals(str4)); //空指针异常
        System.out.println(str4.equals(str3));
    }
}


输出结果:


3c14e2603264497e9c9703b022f5d4c0.png


注意,在程序清单14中,str3 和 str4 不能互换位置,因为 str3 这个引用本身不指向任何对象,如果继续使用 str3 的话,会造成空指针异常,我已经通过注释标明出来了。


在程序清单15中,我们对程序清单14做出了一些改变,当我们忽视大小写的时候,可以使用 equalsIgnoreCase( ) 方法。


程序清单15:


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


输出结果:


745bf988cd4840e286d66253bbfe220c.png


2. compareTo( ) 方法


当查看底层代码,我们发现 String 类型实现了 Comparable接口,那么String 类就会重写 compareTo( ) 方法,返回值是整型。


fe671efa4f4a41dfaaa742edc4bc7aac.png


接下来,我们通过程序清单16来演示一下 compareTo( ) 方法是怎么使用的。


程序清单16:


public class Test16 {
    public static void main(String[] args) {
        String str1 = "abc";
        String str2 = "ABC";
        int ret1 = str1.compareTo(str2);
        System.out.println(ret1);
        System.out.println("--------------");
        String str3 = "abc";
        String str4 = "acb";
        int ret2 = str3.compareTo(str4);
        System.out.println(ret2);
        System.out.println("--------------");
        String str5 = "abcde";
        String str6 = "ab";
        int ret3 = str5.compareTo(str6);
        System.out.println(ret3);
    }
}


输出结果:


cc246fa815674f9ebcd2e401e47a86b0.png

在程序清单16中,compareTo( ) 方法是通过对比字符串中的字符一个一个进行比较的,字符对应的 Unicode 编码之差就是返回值( ASCII 码 )。如果两个字符串长度不等,返回的就是字符串长度之差。

目录
相关文章
|
27天前
|
API 索引
String类下常用API
String类下常用API
32 1
|
27天前
for循环和String类下方法的一个练习题
for循环和String类下方法的一个练习题
42 1
|
3天前
|
存储 安全 Java
Java——String类详解
String 是 Java 中的一个类,用于表示字符串,属于引用数据类型。字符串可以通过多种方式定义,如直接赋值、创建对象、传入 char 或 byte 类型数组。直接赋值会将字符串存储在串池中,复用相同的字符串以节省内存。String 类提供了丰富的方法,如比较(equals() 和 compareTo())、查找(charAt() 和 indexOf())、转换(valueOf() 和 format())、拆分(split())和截取(substring())。此外,还介绍了 StringBuilder 和 StringJoiner 类,前者用于高效拼接字符串,后者用于按指定格式拼接字符串
10 1
Java——String类详解
|
29天前
|
Java API 索引
【Java基础面试二十四】、String类有哪些方法?
这篇文章列举了Java中String类的常用方法,如`charAt()`、`substring()`、`split()`、`trim()`、`indexOf()`、`lastIndexOf()`、`startsWith()`、`endsWith()`、`toUpperCase()`、`toLowerCase()`、`replaceFirst()`和`replaceAll()`,并建议面试时展示对这些方法的熟悉度,同时深入理解部分方法的源码实现。
【Java基础面试二十四】、String类有哪些方法?
|
28天前
|
存储 SQL Java
Java 系类之 Java StringBuffer类详解
这篇文章详细介绍了Java中的StringBuffer类的使用,包括其构造方法、追加字符串、替换字符、反转字符串和删除字符串的方法,并提供了相应的示例代码。
|
28天前
|
安全 Java API
Java系类 之 String、StringBuffer和StringBuilder类的区别
这篇文章讨论了Java中`String`、`StringBuffer`和`StringBuilder`三个类的区别,其中`String`是不可变的,而`StringBuffer`是线程安全的可变字符串类,`StringBuilder`是非线程安全的可变字符串类,通常在单线程环境下性能更优。
Java系类 之 String、StringBuffer和StringBuilder类的区别
|
14天前
|
存储 C++
C++(五)String 字符串类
本文档详细介绍了C++中的`string`类,包括定义、初始化、字符串比较及数值与字符串之间的转换方法。`string`类简化了字符串处理,提供了丰富的功能如字符串查找、比较、拼接和替换等。文档通过示例代码展示了如何使用这些功能,并介绍了如何将数值转换为字符串以及反之亦然的方法。此外,还展示了如何使用`string`数组存储和遍历多个字符串。
|
1月前
|
安全 程序员 C++
C++ --> string类的使用(详细介绍)
C++ --> string类的使用(详细介绍)
37 5
|
1月前
|
存储 编译器 C语言
C++ --> string类模拟实现(附源码)
C++ --> string类模拟实现(附源码)
56 4
|
1月前
|
安全 Java
12 Java常用类(二)(String类+时间类+BigDecimal类等等)
12 Java常用类(二)(String类+时间类+BigDecimal类等等)
25 2