1. String 是引用类型,但它在作为参数传递是值传递,所以一旦修改,会重新指派新的引用,故此时的hashCode(hashCode与地址无关,只与具体的值有关)会发生改变,它的取值是是从StringPool中去获取,如果没有就会创建,并将引用传String对象,请看以下案例
case 1: 到底是值传递还是引用传递
static void replace(String arg){
System.out.println(arg.hashCode()); // 1.
arg = arg.replace("a", "c");
System.out.println(arg.hashCode()); // 2. 此处与1的值不一样
}
public static void main(String[] args){
String arg = "abc";
System.out.println(arg.hashCode()); // 3.此处与1的值一样
replace(arg);
System.out.println(arg.hashCode()); //4.此处与1的值一样
}
请看JDK说明:
* 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.
case 2: 创建了多少对象
public static void main(String[] args){
String arg = "abc";
System.out.println(arg == "ab" + "c"); // true 其比较原理是,首先会将"ab" + "c" 拼接,在Java中以"ab" + "cd" + "ef"类似情况出现的,都只会创建一个String对象,请注意这里是对象,有人说”ab"是会创建一个String对象,在这里此时创建了4个对象,其实是错的,可以在程序运行时,查看JVM,你会发现在所有的String实例中并没有"ab", "cd", "ef"的实例,只有"abcdef"的实例,充分说明只创建了一个String对象。不难理解在它们没有完成拼接前,它们都不是一个String的实例,只是一个简单的值,那么问题来了,既然不是对象怎么能够拼接运算?怎么能够使用String的方法? 其实这跟Java的编译机制有很大的关系,我们可以查看相应的class文件,你会发现类似下面的信息:
SOH NUL STXabBS NUL!SOH NUL SOHcBEL NUL#SOH NUL ETB java/lang/StringBuilder
不难发现,在编译时期就已经使用了StringBuilder对象进行运算,并且把“ab" + "c"这种类似的情形当做一个块来处理(STX(块始) ETB(块终)),所以到了运行期间,执行此种类似语句,其实只需要简单值运算下,再将运算的结果放入StringPool,此时便是一个String的对象,接着就可以充当String的实例,不难发现本例中的的 arg == "ab" + "c"其实就是: "abc" == "abc";你说这是不是应该为true.
String arg2 = "ab";
String arg3 = "c";
System.out.println(arg == arg2 + arg3); // false 很奇怪吗,其实一点都不奇怪,arg2 + arg3是运行时计算出来的(这种运算不能与上同日而语),不会放入StringPool池中去,其本身在方法执行栈中,且为暂态(因为没有将其它引用,故这种中间运算结果很快会被释放)
String arg4 = "ab" + "c" ;// 只创建一个对象
String arg5 = "abcde" ;// 只创建一个对象
String arg6 = new String("abcd") ; //创建了2个对象
}
case 3: 有趣的hashCode 和 equals;
其实String对象的hashCode的核心算法,精简了一下
int hash = 0;
value to char array chs;
for: chs
hash = 31 * hash + chs[i]
由此可知,通过比较hashCode也可以判断两个String的对象是否相等,但通常不这样做,也说明了hashCode不等于地址,由此有:
String arg7 = "abc";
String arg8 = "ab";
String arg9 = "c";
System.out.println(arg7.hashCode() == (arg8 + arg9).hashCode()) // true
System.out.println(arg7 == (arg8 + arg9)); // false
eqals方法的核心算法有类似之处:
if another == this.value
then return true;
this.value to char array schs;
another to char array chs;
if(schs.length == chs.length)
for: chs
if(chs[i] == schs[i])
return true;
return false;