【小白的java成长系列】——String类的深入分析(基于源码)

接着前面面向对象来说吧~今天来说说String类。。其实String类也包含很多面向对象的知识的~

首先来问一个问题:我们在开发过程中,如果要使用一个类的话,就要创建对象,这句话没什么问题吧~在实际开发的时候确实是这样的,只有创建了对象才能真正的去使用一个普通的类,我们一般创建对象,几乎所有的类创建对象都是要通过new关键字来创建的~

问题就来了。。为什么我们的String可以直接写成String str = "abc";这样子呢?

当然String类也可以通过new来创建对象的。。。

其实也不难,我们看到它的源码说明就知道的:

 * Strings are constant; their values cannot be changed after they
 * are created. String buffers support mutable strings.
 * Because String objects are immutable they can be shared. For example:
 * <p><blockquote><pre>
 *     String str = "abc";
 * </pre></blockquote><p>
 * is equivalent to:
 * <p><blockquote><pre>
 *     char data[] = {'a', 'b', 'c'};
 *     String str = new String(data);
 * </pre></blockquote><p>

进入String的源码,最前面就能看到上面的文字的:大致的意思是,String的对象值其实是通过char[]数组来存储的,String str = "abc";等同于char data[] = {‘a‘, ‘b‘, ‘c‘};  String str = new String(data);明白清晰了吧~

1、String类的定义:

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

问题:在开发过程中,我们可以继承String类吗?

答案:不行的,我们看定义就知道,String的定义使用了final修饰符,定义为了终结类,所以String是不能做扩展的。

implements:这个关键字是用来表示实现接口作用的,意思就是Serializable、Comparable和CharSequence都是接口的。

查看接口源码:

Comparable<T>  :表示比较器作用,<T>采用了java泛型的形式

Serializable:

public interface Serializable {
}

我们可以看到Serializable接口里面啥都木有,那为什么我们要实现这个接口呢?这个接口的作用是啥呢?

作用:java类的序列化,至于序列化,后面会详细介绍。其实Serializable是java的一个标记接口,什么叫标记接口?Serializable只是作为一个标记的作用,关于它具体的功能和作用交给了JVM底层去实现了,实现了这个接口,只是通知JVM,String这个类可以序列化。

CharSequence:表示字符序列吧~这个没啥好说的,String的存储方式依赖于字符序列的~


2、属性

    private final char value[];	//String值就是存储在value[]上的

    private int hash; // Default to 0  表示hash值,


    private static final long serialVersionUID = -6849794470754667710L;//序列化作用

    private static final ObjectStreamField[] serialPersistentFields =
            new ObjectStreamField[0];//序列化作用

我们只要了解String类的属性就可以,几乎都不会用到的,因为都是定义成了private,私有化了~

3、构造方法

这里也只说几个特殊的,一般在开发过程中也不会用到构造方法的,因为很少使用new来创建String对象的,都是直接使用String str = "abc";这样子的形式。。

在面试过程中,很多面试官会问到String str = new String("abc");这个创建了几个对象?至于答案和解释,这边就不做介绍了,想知道的就去网上查找了解~这个涉及到底层的内存问题的,描述起来篇幅会很长的~

    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }
从上面可以看到,String两个核心就是value和hash的,这两个值基本决定了String对象的。

    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }
这个是通过底层数组拷贝的方式创建,其实底层使用的是System.arrayCopy()这个方法,此方法使用了native修饰的,底层是由C/C++来实现的,其实就是一个拷贝的作用

public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(bytes, offset, length);
    }
这个表示的是通过字节(byte)来构造字符串,其实底层的实现也是通过System.arrayCopy()这个方法的。

其他的基本也没什么好说的,了解一下就可以的。我们可以看到有些构造使用了@Deprecated注解,这个注解表示的过时,不推荐使用这个方法的

4、常用方法

    public int length() {	//返回字符串长度
        return value.length;
    }

	public boolean isEmpty() {//判断字符串是不是为空
        return value.length == 0;
    }

	public char charAt(int index) {//字符串中的某个字符,index表示字符的位置
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }

	public byte[] getBytes() {//获取字节数组
        return StringCoding.encode(value, 0, value.length);
    }

	public boolean equals(Object anObject) {//字符串比较,我们知道基本类型的比较都是通过==来做比较的,
						//但是字符串需要使用此方法来做比较的

我们主要来验证一下==和equals方法

package me.javen.oop;

public class StringDemo {

	public static void main(String[] args) {
		String str1 = "hello" ;					// 直接赋值
		String str2 = new String("hello") ;		// 通过new赋值
		String str3 = str2 ;					// 传递引用
		System.out.println("str1 == str2 --> " + (str1==str2)) ;	// false
		System.out.println("str1 == str3 --> " + (str1==str3)) ;	// false
		System.out.println("str2 == str3 --> " + (str2==str3)) ;	// true
		
		//以下通过equals方法
		System.out.println("str1 equals str2 --> " + (str1.equals(str2))) ;	// true
		System.out.println("str1 equals str3 --> " + (str1.equals(str3))) ;	// true
		System.out.println("str2 equals str3 --> " + (str2.equals(str3))) ;	// true
	}

}
此外还有一个比较方法也用得比较多:

public boolean equalsIgnoreCase(String anotherString) {//不分大小写比较

	public boolean startsWith(String prefix) {//判断字符串是不是以prefix开头
	public boolean endsWith(String suffix) {//判断字符串是不是以suffix结尾
	public int hashCode() {//获取字符串的hash值
	public int indexOf(String str) {//获取字符str的起始位置,-1表示没有这个字符
        return indexOf(str, 0);
    }

	public String substring(int beginIndex, int endIndex) {//截取字符串beginIndex表示起始位置,endIndex表示结束位置
	public String replaceAll(String regex, String replacement) {//字符串替换replacement替换regex

	public String[] split(String regex) {//分隔字符串,regex表示分隔符

	public String toLowerCase() {//将字符串全部转换为小写
	public String toUpperCase() {//将字符串全部转换为大写
	
	public String trim() {//去掉首尾空格,字符中间的空格不能去掉

	public static String valueOf(Object obj) {//将obj转换成字符串,这个可以传递任意类型,比如数字,字符,浮点数等等

此外还有其他的很多方法,这边就不列举出了,学习者可以通过代码的方式去使用这些个方法,列举出来的表示开发中常用的方法~

【小白的java成长系列】——String类的深入分析(基于源码),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。