String的那些事

栏目: IT技术 · 发布时间: 4年前

内容简介:通过查看String类的源码我们得知:String类被final关键字修饰,这即是说明String类的特点就是:字符串对象一旦被初始化就不会被改变。注意:此处是字符串对象而不是字符串引用。也即是说:那么String类被final修饰有什么好处呢?第一个好处是安全,因为final保证不管怎样操作,它的值都是不变的;第二个好处就是高效,因为只有String类是不可变类时,我们才能实现字符串常量池。试想如果String类是可变类,当多个字符串引用变量指向同一个字符串对象时,字符串对象改变后就会引起多个字符串引用变

String的特点?

通过查看String类的源码我们得知:String类被final关键字修饰,这即是说明String类的特点就是:字符串对象一旦被初始化就不会被改变。注意:此处是字符串对象而不是字符串引用。也即是说:

String s = "abc";   // s引用变量指向了值为"abc"的对象

s = "cba";    // s引用变量又指向了值为"cba"的对象,但是上面值为"abc"的对象的值并未改变

那么String类被final修饰有什么好处呢?第一个好处是安全,因为final保证不管怎样操作,它的值都是不变的;第二个好处就是高效,因为只有String类是不可变类时,我们才能实现字符串常量池。试想如果String类是可变类,当多个字符串引用变量指向同一个字符串对象时,字符串对象改变后就会引起多个字符串引用变量内容的改变,这显然不符合我们的预期。我们可以通过下面的代码来验证字符串常量池的存在:

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

        Demo d1 = new Demo();
        Demo d2 = new Demo();
        System.out.println(s1 == s2);     // 1
        System.out.println(d1 == d2);
    }
}

我们知道:如果是两个引用变量使用"=="进行比较,那么比较的是两个对象的地址值,1处的代码输出结果为"true",说明s1引用变量和s2引用变量指向的是同一个对象,也就验证了字符串常量池的存在。字符串常量池其实就是字符串的一个缓冲区,而"缓存"可以提高系统性能,那么即是说字符串常量池的使用可以提高系统性能。常量池的特点就在于:如果池中没有则创建,如果池中有就直接使用池中的。

String内部实际存储结构为char数组。下面为jdk1.8版本的String源码:

public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {

    // 用于存储字符串的值
    private final char value[];

    // 用于缓存字符串的hashcode
    private int hash; // Default to 0

    // else code
    // ... ...
}

我们需要注意编译器会对String做一些优化,比如下列代码:

class Demo {
    public static void main(String[] args) {
        String s1 ="Ja"+"va";
        String s2 = "Java";
        System.out.println(s1 == s2);
    }
}

String的构造方法?

String是一个类,所以我们除了使用String s1 = "abc"方式创建字符串对象之外,还可以通过String类的构造方法进行创建。通过查看jdk文档我们发现String类

有下面这样的构造函数:

String的那些事

我们需要注意这两种创建方式的区别:

class Demo {
    public static void main(String[] args) {
        String s1 = newString("Java");   // 1
        String s2 = s1.intern();         // 2
        String s3 = "Java";              // 3
        System.out.println(s1 == s2);
        System.out.println(s2 == s3);
    }
}

1处代码的含义是:在堆内存中使用new的方式创建了一个字符串对象并把地址值赋给了引用变量s1,并且该对象在创建的时候接收了一个字符串对象;而2处代码的含义是:在堆内存中创建一个变量s2,如果调用intern()才会把此字符串保存到字符串常量池中(关于intern方法,下面还会提到);3处代码的含义是:在字符串常量池中创建了一个值为"Java"的字符串对象,并把该对象的地址值赋给了引用变量s3;所以3处的代码最终只创建了一个对象,而1处的代码有可能创建一个(字符串常量池中有字符串对象"Java")也有可能创建两个(字符串常量池中没有字符串对象"Java")。这三个引用变量在JVM中存储的位置如下:

String的那些事

我们可以看到引用变量s1和引用变量s2的内容其实是相等的,都是"Java",于是如果我们只想比较两者的内容时,就可以使用equals()。

class Demo {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = new String("abc");

        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
    }
}

这里需要注意,Object类中equals()的源码是下面这样的:

public boolean equals(Object obj) {
    return (this == obj);   // 比较的还是对象的地址值
}

而String类对该方法进行了覆盖,源码是这样的:

public boolean equals(Object anObject) {
    // 对象引用相同直接返回 true
    if (this == anObject) {
        return true;
    }

    // 判断需要对比的值是否为String类型,如果不是则直接返回false
    if (anObject instanceof String) {   
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            // 把两个字符串都转换为 char 数组对比
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;

            // 循环比对两个字符串的每一个字符
            while (n-- != 0) {

                // 如果其中有一个字符不相等就 true false,否则继续对比
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

String类有几个很常用的构造方法,如下:

// char[]为参数的构造方法
public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

// byte[]为参数的构造方法
public String(byte bytes[]) {
    this(bytes, 0, bytes.length);
}

// string为参数的构造方法
public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

// StringBuffer为参数的构造方法 
public String(StringBuffer buffer) {
    synchronized(buffer) {
        this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
    }
}

// StringBuilder为参数的构造方法  
public String(StringBuilder builder) {
    this.value = Arrays.copyOf(builder.getValue(), builder.length());
}

String的常用方法?

通过查看jdk文档,我们可以看到String类有很多方法,将其中常用的方法分为下面几类:

  • 用于获取:
1.1 获取字符串中字符的个数(长度):
        int length();
1.2 根据位置获取字符:
        char charAt(int index);
1.3 根据字符获取在字符串中的第一次出现的位置:
        int indexOf();    // 注意此方法的有多种重载形式
  • 用于转换
1.1 将字符串变成字符串数组(字符串的切割):
        String[]  split(String regex);   // 注意此方法涉及到正则表达式
1.2 将字符串中的字母转成大小写:
        String toUpperCase():大写
        String toLowerCase():小写
1.3 将字符串中的内容进行替换:
        String replace();
1.4 将字符串两端的空格去除:
        String trim();
  • 用于判断
1.1 判断字符串中是否包含指定字符串:
        boolean contains(string str);
  • 用于比较
1.1 比较两个字符串:
        int compareTo(String anotherString)

// 下面为compareTo方法的源码
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;
}

可以看出compareTo()和equals()都是用于比较两个字符串的,并且当equals()返回true或者是compareTo()返回0时,则表示两个字符串完全相同。这两个方法的区别在于:compareTo()接收的是String类型的参数,而equals()可以接收一个Object类型的参数;compareTo()的返回值为int,而equals()返回值为Boolean。


以上所述就是小编给大家介绍的《String的那些事》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learn Python the Hard Way

Learn Python the Hard Way

Zed A. Shaw / Addison-Wesley Professional / 2013-10-11 / USD 39.99

Master Python and become a programmer-even if you never thought you could! This breakthrough book and CD can help practically anyone get started in programming. It's called "The Hard Way," but it's re......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码