JAVA String类
之前提到过String也是引用类型之一,具有很多的方法和属性,那么我们平时开发中,必须要熟练使用这个方法和属性,并且了解String对象在内存中的使用。
在API中是这样描述:
String 类代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。
字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。
字符串常量池(String Pool)
Java中的字符串常量池(String Pool)是存储在Java堆内存中的字符串池,String对象均存放在这个池子里面。
String的创建
String的创建有下面两种方式:
- 直接赋值
String s = "123";
- 使用new创建
String s = new String("123");
这种方式实际上就是使用String的构造器创建对象,查看相关源码就能看到
public final class String
implements java.io.Serializable, Comparable<String>, 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
* <a href="{@docRoot}/../platform/serialization/spec/output.html">
* Object Serialization Specification, Section 6.2, "Stream Elements"</a>
*/
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;
}
// ...此处省略
」
那么这两种方式的区别是什么呢?
- 直接赋值:首先先去查找堆内存的字符串常量池中,存不存在该字符串,假如没找到,则会重新创建一个;假如找到了,那么就会直接去引用该字符串,而不进行创建,这样能够大量的节省内存空间并提升效率。就像下面的代码
public static void main(String[] args) { String str1 = "Hello"; String str2 = "Hello"; String str3 = "Hello"; }
这其实是个障眼法,其实就是在栈内存中放了三个变量,堆内存中始终就只有那一个家伙 “Hello”,这三个变量同时指向了这个家伙。
- 使用new创建:此时创建字符串的时候,会在堆内存的字符串常量池中重新开辟一块内存,储存该字符串常量,使用完毕后,由GC进行回收。
public static void main(String[] args) { String str1 = "Hello"; String str2 = "Hello"; String str3 = new String("Hello"); // 重新在堆中创建了一个对象 }
这边就不一样了,这时候在栈中还是一样的存放了三个变量,而在堆中这个时候是有了两个长相一样的家伙 “Hello”,此刻str1和str2指向第一个家伙,而str3则指向了后来的那个家伙。假如你们不信,那么我们用事实说话!看下面!
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello"); // 重新在堆中创建了一个对象
System.out.println(str1 == str2); // 判断str1和str2在内存中是否一个对象,输出true
System.out.println(str1 == str3); // 判断str1和str3在内存中是否是一个对象,输出false
}
常用的String Api
可以看到,我上面截的图,真的是很多方法啊,我就偷下懒吧,直接贴出来,下面的练习由你们自己完成啦!加油
更多的API请查看官方文档,最全最详细!满足你!
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html
如果看不懂英文,那就看下面这个