java 中的string_深入理解Java中的String

前言

String 类我们在写代码的时候是用的最多的一种类了,那么我们有深入理解它吗?想深入理解Java中的String,那么就要分析源码

分析String源码

public final class String

implements java.io.Serializable, Comparable, CharSequence {

/** The value is used for character storage. */

private final char value[];

/** Cache the hash code for the string */

private int hash; // Default to 0

/** use serialVersionUID from JDK 1.0.2 for interoperability */

private static final long serialVersionUID = -6849794470754667710L;

/**

* Class String is special cased within the Serialization Stream Protocol.

*

* A String instance is written into an ObjectOutputStream according to

*

* Object Serialization Specification, Section 6.2, "Stream Elements"

*/

private static final ObjectStreamField[] serialPersistentFields =

new ObjectStreamField[0];

/**

* Initializes a newly created {@code String} object so that it represents

* an empty character sequence. Note that use of this constructor is

* unnecessary since Strings are immutable.

*/

public String() {

this.value = "".value;

}

/**

* Initializes a newly created {@code String} object so that it represents

* the same sequence of characters as the argument; in other words, the

* newly created string is a copy of the argument string. Unless an

* explicit copy of {@code original} is needed, use of this constructor is

* unnecessary since Strings are immutable.

*

* @param original

* A {@code String}

*/

public String(String original) {

this.value = original.value;

this.hash = original.hash;

}

.....

复制代码

1.从源码分析,String 是一个 final 类,说明是不能被继承的类

2.String自身继承Serializable,Comparable,CharSequence三个接口,说明String也有它们3个接口的功能,可以序列号,排序,可读序列

String类代表字符串。Java程序中的所有字符串,如 "abc",实现为这个类的实例。

字符串常量,它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为他们可以共享字符串对象是不可变的。例如:

String str = "abc";

复制代码

等价于:

char data[] = {'a', 'b', 'c'};

String str = new String(data);

复制代码

这里有一些如何使用字符串的更多示例:

System.out.println("abc");

String cde = "cde";

System.out.println("abc" + cde);

String c = "abc".substring(2,3);

String d = cde.substring(1, 2);

复制代码

类String包括方法研究单个字符的序列,来比较字符串,搜索字符串,提取子字符串,用于创建一个字符串的副本与所有字符转换为大写或小写。情况下映射基于Unicode标准版Character指定的类。

Java语言提供特殊支持字符串连接操作符(+),和其他对象转换成字符串。字符串连接实现通过StringBuilder(或StringBuffer)类及其append方法。toString字符串转换是通过实现的方法,定义为Object和继承的所有Java类

除非另外注明,null参数传递给这个类的构造函数或方法将导致NullPointerException抛出。

分析方法

public String concat(String str) {

int otherLen = str.length();

if (otherLen == 0) {

return this;

}

int len = value.length;

char buf[] = Arrays.copyOf(value, len + otherLen);

str.getChars(buf, len);

return new String(buf, true);

}

public String replace(char oldChar, char newChar){

if (oldChar != newChar) {

int len = value.length;

int i = -1;

char[] val = value; /* avoid getfield opcode */

while (++i < len) {

if (val[i] == oldChar) {

break;

}

}

if (i < len) {

char buf[] = new char[len];

for (int j = 0; j < i; j++) {

buf[j] = val[j];

}

while (i < len) {

char c = val[i];

buf[i] = (c == oldChar) ? newChar : c;

i++;

}

return new String(buf, true);

}

}

return this;

}

复制代码

可以看到一些方法concat,replace都是自身的操作,发现到最后都是从新生成一个String对象,也就是说最原始的对象还是存在的。

所以可以得到一个结论:String类一旦创建就不会改变,对String对象做任何操作都会影响原始数据,相关的方法会创建一个新的String对象。

常量池

在 JAVA 语言中有8中基本类型和一种比较特殊的类型String。这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念。常量池就类似一个JAVA系统级别提供的缓存。8种基本类型的常量池都是系统协调的,String类型的常量池比较特殊。它的主要使用方法有两种:

1.直接使用双引号声明出来的String对象会直接存储在常量池中。

2.如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中

String s1 = "abc";

String s2 = "abc";

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

复制代码

结果是 true;

采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"abc"这个对象,如果不存在,则在字符串常量池中创建"abc"这个对象,然后将池中"abc"这个对象的引用地址返回给"abc"对象的引用s1,这样s1会指向字符串常量池中"abc"这个字符串对象;如果存在,则不创建任何对象,直接将池中"abc"这个对象的地址返回,赋给引用s2。因为s1、s2都是指向同一个字符串池中的"abc"对象,所以结果为true。

String s3 = new String("xyz");

String s4 = new String("xyz");

System.out.println(s3==s4);

复制代码

结果是 false

采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"xyz"这个字符串对象,如果有,则不在池中再去创建"xyz"这个对象了,直接在堆中创建一个"xyz"字符串对象,然后将堆中的这个"xyz"对象的地址返回赋给引用s3,这样,s3就指向了堆中创建的这个"xyz"字符串对象;如果没有,则首先在字符串池中创建一个"xyz"字符串对象,然后再在堆中创建一个"xyz"字符串对象,然后将堆中这个"xyz"字符串对象的地址返回赋给s3引用,这样,s3指向了堆中创建的这个"xyz"字符串对象。s4则指向了堆中创建的另一个"xyz"字符串对象。s3 、s4是两个指向不同对象的引用,结果当然是false。

Intern的实现原理

/**

* Returns a canonical representation for the string object.

*

* A pool of strings, initially empty, is maintained privately by the

* class {@code String}.

*

* When the intern method is invoked, if the pool already contains a

* string equal to this {@code String} object as determined by

* the {@link #equals(Object)} method, then the string from the pool is

* returned. Otherwise, this {@code String} object is added to the

* pool and a reference to this {@code String} object is returned.

*

* It follows that for any two strings {@code s} and {@code t},

* {@code s.intern() == t.intern()} is {@code true}

* if and only if {@code s.equals(t)} is {@code true}.

*

* All literal strings and string-valued constant expressions are

* interned. String literals are defined in section 3.10.5 of the

* The Java™ Language Specification.

*

* @return a string that has the same contents as this string, but is

* guaranteed to be from a pool of unique strings.

*/

public native String intern();

复制代码

String#intern方法中看到,这个方法是一个 native 的方法,但注释写的非常明了。“ 当调用 intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(oject)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值