String类对象存储地址问题

  • String  equals(String s):比较的是字符串内容是否相等;
  • == : 比较的是存储地址是否相等;

创建字符串对象方式:

String s = "hello";
String s1 = new String("hello");
String s2 = "hello" + "world";
String s3 = s1 + s2;
.......

下面我们主要利用 == 研究一下在创建字符串对象时不同的创建方法,其存储位置有何不同:

public class stringTest {
    
    /** 创建了三个对象,"helloworld对象创建在常量池中",每次new String()都会创建一个对象在堆内存中工两个堆对象。
     * 
     */
    void test() {
        String s1= new String("helloworld");
        String s2= new String("helloworld");
        System.out.println("test()"+ (s1==s2));//false
    }
    /**程序只创建一个字符串对象“Java”,存放在常量池中,所以s1==s2 为true
     * 
     */
    void test1(){
        String s1="Java";
        String s2="Java";
        System.out.println("test1()"+ (s1==s2));//true
       
    }
    
    /** 第一个new String("Java"):创建了两个对象,Java创建于常量池中,String对象创建于堆内存中。
     * 第二个new String("Java"):由于常量池中有Java对象,所以只需创建一个对象,String对象创建于堆内存中。
     * s1与s2分别指向String对象堆内存,所以s1==s2 为false
     */
    void test2() {
        String s1=new String("Java");
        String s2= new String("Java");
        System.out.println("test2()"+ (s1==s2));//false
    }
    
    /** 常量的值在编译的时候就确定了,"hello"、"world"都是常量,因此s2的值在编译的时候也确定了,
     * s2指向常量池中的"hello world",所以s1==s2为true
     * 
     */
    void test3() {
        String s1="hello world";
        String s2="hello "+"world";
        System.out.println("test3()"+ (s1==s2));//true
    }
    
    /** s4由两个String变量相加得到,不能再编译时就确定下来,不能直接引用常量池中的"helloworld"对象,而是在堆内存中创建一个新的String对象并由s4指向
     * 所以s1==s4为false
     *
     */
    void test4() {
        String s1="helloworld";
        String s2="hello";
        String s3="world";
        String s4=s2+s3;//String s4 = new String(s2+s3);
        System.out.println("test4()"+ (s1==s4));//false
    }
    
    /** s2与s3被final修饰为宏变量,不可更改,编译器在程序使用该变量的地方直接使用该变量的值进行替代,所以s4的值在编译的时候就为"helloworld"
     * 指向常量池中的"helloworld"对象
     * 所以s1==s4为true
     * 
     */
    void test5() {
        String s1="helloworld";
        final String s2="hello";
        final String s3="world";
        String s4=s2+s3;
        System.out.println("test5()"+ (s1==s4));//true
    }
    /**
     * s4由两个String变量相加得到,不能再编译时就确定下来,不能直接引用常量池中的"helloworld"对象,而是在堆内存中创建一个新的String对象并由s4指向
     * 同样的,s5也是由两个String变量s2和s3相加.
     * s5和s4指向的堆中空间中的字符串虽然都是hellowrold,但是s5和s4指向的地址不一样,因此返回false
     * 可以理解为:
     * String s4=s2+s3; -->String s4 = new String(s2+s3);
     * String s5= s2+s3;//String s5 = new String(s2+s3);
     */
    void test6() {
    	String s1="helloworld";
        String s2="hello";
        String s3="world";
        String s4=s2+s3;//String s4 = new String(s2+s3);
        String s5= s2+s3;//new String(s2+s3)
        System.out.println("test6()" + (s4 == s5));//false
    }
    /**
     * s2+s3 -->  new String(s2+s3);
     * s2+s3 -->  new String(s2+s3);
     * 虽然是两个相同的操作,可以看作在堆中创建了两个匿名对象。
     * 操作相同,但是空间地址依然不同。
     * 所以(s2+s3 == s2+s3)返回false
     */
    void test7() {
    	String s1="helloworld";
        String s2="hello";
        String s3="world";
        System.out.println("test7()" + (s2+s3 == s2+s3));//false
    }
    public static void main(String[] args) {
        stringTest t = new stringTest();
        //分别测试
        t.test();
        t.test1();
        t.test2();
        t.test3();
        t.test4();
        t.test5();
        t.test6();
        t.test7();
        
    }
}

运行结果如下: 

 

当用String 创建对象时:

1.String s = "hello";    "hello"在常量池中,栈中的s直接指向了常量池中的“hello”

 2.String s1 = new String("java");  "java"先出现在常量池中,接下来再在堆中创建对象指向"java";

3.只要有new,那么必然是在堆中新开辟了一个内存空间,而堆中的内存空间地址都是不一样的。

4.只要有“=”号,即只要有赋值号,那么必然发生了地址的改变。

5.编译只检查语法错误,并将常量地址赋值,对变量仅仅是检查语法错误,因此执行String s3 = s1 + s2;会在运行时在堆中开辟空间,等同于 String s3 = new String(s1+s2);

6.只要不是直接指向常量,而是间接通过堆来指向常量池中的常量,那么即使字符串内容相同,那么地址也是不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值