本文对String类的以下问题作出分析:
1、字符串比较 “==” 与 equals()的区别
2、字符串常量是String类的匿名对象 ObjectPool
3、字符串常量是不可改变的
4、两种实例化的区别 匿名对象与new
5、null与String的关系
1、字符串比较 “==” 与 equals()的区别
"==" 是进行数值比较,如果用在字符串对象比较上,比较的是两个对象的内存地址数值,即比较的是两个字符串是否放置在同一位置。
“equals()” 是String类中定义的方法(public boolean equals(String str)),可以用来比较字符串内容。
equals()函数还具有自动判空功能,如果参数为null,则比较结果直接返回false,如果需要判断用户输入的字符串是否为指定字符串是,一般用如下代码:
String InputStr = "Hello";
//InputStr.equals("Hello"); 不使用这句,如果用户输入InputStr为空,则会出现空指向的报错。
"Hello".equals(InputStr);
在引用数据类型操作中,永远都可以使用“==”进行比较,而比较的永恒是地址数值。
java源码中对String类的 equals() 方法的定义如下:可以作为日后写对象比较时 equals() 方法的参考。
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) { // 判断是否为空,因为 null 不属于 String 类
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
2、字符串常量是String类的匿名对象 ObjectPool
因为字符串的频繁使用,Java的String类里面有共享设计思想。如果定义字符串的匿名对象,没有对象名指向此匿名对象,该对象内容不会被当做垃圾回收,会保存在Objectpool中,当有字符串再次定义为此匿名对象的内容时,可直接将字符串名指向Objectpool中的该对象内存即可。
String strA = "Hello"; //Hello 将被保存在ObjectPool中,不会被GC回收
String strB = "Hello"; //此时strB直接指向 ObjectPool中的"Hello",二者地址相同
String strC = new String("Hello");
System.out.println(strA == strB); // “==”用于字符串比较是,是对象名所保存的地址值的比较
System.out.println(strA == strC);
System.out.println(strB == strC);
//输出结果:
//true
//false
//false
3、不可变字符串
由于不能Java字符串不能修改,所以子Java文档中将String类对象称为不可变字符串。不可变字符串有一个优点:编译器可以让字符串共享,字符串会存放在公共的存储池中。每次给字符串变量重新赋值的时候其实是更改变量的引用,如下:
String A = "hello!" ; //
A = "help!" // 不是将"hello!"所在区域重新赋值,而是新开辟空间,初始为"help!",然后更改变量A的引用,为"help!"
Java的设计者认为共享带来的高效率远远胜过字符串提取、拼接带来的低效率,因为大部分程序很少需要修改字符串,而更多的是对字符串进行比较。
4、两种实例化的区别 匿名对象与new
匿名对象实例化: String strA = “Hello”;
构造方法实例化对象:String strB = new String(“Hello”);
匿名对象实例化时,Hello取自ObjectPool中的内容,如果内容不在ObjectPool中,则开辟空间,赋值此内容,并放入ObjectPool中,不会多次开辟内存。
new开辟字符串对象时,参数“Hello”为匿名对象(之后变为垃圾),之后new会在堆中再次开辟内存,将之前参数“Hello”保存在new开辟的内存中,有StrB指向该new开辟的内存,会产生空间浪费。构造方法实现的实例化,字符串不会自动入池(ObjectPool),但是可以收到入池(使用intern()函数)。
// intern()的使用
String.intern();
strA.intern();
5、null与String的关系
String默认值为null,但是null却不是String类别(instanceof判断)
class People {
private String name;
public People() {}
public People(String name) {
if (name instanceof String) {
this.name = name ;
}
else{
System.out.println("you input name is error@!");
this.name = "error name" ;
}
}
public String getInfo(){
return this.name ;
}
}
public class Demo {
public static void main(String args[]) {
People pa = new People() ;
System.out.println(pa.getInfo()) ; // null
People pb = new People(null) ; // you input name is error@!
System.out.println(pb.getInfo()) ; // error name
System.out.println(null instanceof String) ; // false
}
}