package com.lib.String;
//总结
//1、栈中用来存放一些原始数据类型的局部变量数据和对象的引用(String,数组.对象等等)但不存放对象内容
//2、堆中存放使用new关键字创建的对象.
//3、字符串是一个特殊包装类,其引用是存放在栈里的,而对象内容必须根据创建方式不同定(常量池和堆).有的是编译期就已经创建好,存放在字符串常 量池中,而有的是运行时才被创建.使用new关键字,存放在堆中。
//4、final 修饰的StringBuffer 变量是否可以追加。
public class StringTest {
/**
* ab的哈希值 是a的哈希值 左移 5位+1
*/
public static void test1(){
String name = "abc";
String name1 = "b";
System.out.println(name.hashCode()+"---"+name1.hashCode());
int h = 0;
for(int i=0; i<2; i++){
h = 31*h +(97+i);
}
System.out.println(h);
System.out.println((97<<5)+1);
}
/**
* 测试字符串的创建
*/
//答案1:如果常量池中没有 "ab" 值,1个 没有 2个
// JAVA虚拟机首先在字符串池中查找是否已经存在了值为"ab"的这么一个对象,它的判断依据是String类equals(Object obj)方法的返回值。
// 如果有,则不再创建新的对象,直接返回已存在对象的引用;
// 如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回
//答案3:
// 当执行String a="abc";时,JAVA虚拟机会在栈中创建三个char型的值'a'、'b'和'c',然后在堆中创建一个String对象,
// 它的值(value)是刚才在栈中创建的三个char型值组成的数组{'a','b','c'},最后这个新创建的String对象会被添加到字符串池中(重要)。
// 如果我们接着执行String b=new String("abc");代码,由于"abc"已经被创建并保存于字符串池中,
// 因此JAVA虚拟机只会在堆中新创建一个String对象,但是它的值(value)是共享前一行代码执行时在栈中创建的三个char型值值'a'、'b'和'c'。
public static void test2(){
//问题3:执行过程
String a = "ab";
String b = "ab";
String c = "a"+"b"; //1.编译之后就是 String c = "ab";
//2.使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中
//问题1:下面这行代码运行过程中创建了几个对象
String d = new String("ab");
String f = a+b;
String g = a+"b"; //所产生的新对象"aab"不会被加入字符串池中
System.out.println("a ==b "+(a==b)); //true
System.out.println("a ==c "+(a==c)); //true
System.out.println("a ==d "+(a==d)); //false
System.out.println("abab ==f "+(f=="abab"));//false
System.out.println("aab ==g "+(g=="aab")); //false
}
/**
* 模拟 equlas 方法
* 1、先用 == 判断 地址是否相同
* 2、先判断是否是Sting对象
* 3、
*/
public static void test3(){
String a = "ab";
boolean b = a.equals("ab");
}
/**
* final 修饰的类变量
* 重要: 可见,final只对引用的"值"(即内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。
* 至于它所指向的对象 的变化,final是不负责的。
*/
//答案2:可以追加,原因在(重要:)中阐述
public static void test4(){
final StringBuffer a = new StringBuffer("aaa");
//问题2:final 修饰的变量a 是否可以追加?
a.append("bbb");
System.out.println(a.toString());
}
/**
* 测试常量池中是否存在该字符串 intern()方法的使用
*/
public static void test5(){
// 使用char数组来初始化a,避免在a被创建之前字符串池中已经存在了值为"abcd"的对象
String a = new String(new char[] { 'a', 'b', 'c', 'd' });
//String a = "abcd";
//String a = new String("abcd");
//解释来自jdk : 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串(相当于 String b = a;)。
//否则,将此 String 对象添加到池中,并返回此 String 对象的引用。
String b = a.intern();
String c = "abcd";
System.out.println(b==c);
if (b == a) {
System.out.println("b被加入了字符串池中,没有新建对象");
} else {
System.out.println("b没被加入字符串池中,新建了对象");
}
}
//部分来自: http://blog.csdn.net/phantomes/article/details/9789757
public static void main(String[] args) {
//test1();
test2();
// test3();
// test4();
test5();
}
}
empty
String对象创建内存分析浅解
最新推荐文章于 2022-04-21 18:07:36 发布