zoukankan      html  css  js  c++  java
  • Java中String直接赋字符串和new String的一些问题

    今天课堂测试做了几道String的练习题,做完直接心态爆炸......

    整理自下面两篇博客:

    https://www.cnblogs.com/marsitman/p/11248001.html

    https://www.cnblogs.com/aspirant/p/9193112.html

    首先先来看看下面的代码:

    public class StringTest {
        public static void main(String[] args){
            String s1="Hello";
            String s2="Hello";
            String s3=new String("Hello");
            System.out.println("s1和s2 引用地址是否相同:"+(s1 == s2));
            System.out.println("s1和s2 值是否相同:"+s1.equals(s2));
            System.out.println("s1和s3 引用地址是否相同:"+(s1 == s3));
            System.out.println("s1和s3 值是否相同:"+s1.equals(s3));
        }
    }

    打印结果如下:

    s1和s2 引用地址是否相同:true
    s1和s2 值是否相同:true
    s1和s3 引用地址是否相同:false
    s1和s3 值是否相同:true

    我们可以看到 在java中,比较String有两种方式,一种是用"==",另一种是用s.equals()方法。

    那么这两种方法有什么不同呢?

    上面程序中的"=="是判断两个对象引用的地址是否相同,也就是判断是否为同一个对象,s1与s2 返回为true,s1与s3返回则是false。说明s1与s2 引用的同一个对象的地址,s3则与其它两个引用不是同一个对象地址。

    s.equals()方法则是判断字符串的内容是否相等,只要内容相等就返回true,当然,地址相等就更不用说了,肯定返回true。

    Java为了避免产生大量的String对象,设计了一个字符串常量池。工作原理是这样的,创建一个字符串时,JVM首先为检查字符串常量池中是否有值相等的字符串,如果有,则不再创建,直接返回该字符串的引用地址,若没有,则创建,然后放到字符串常量池中,并返回新创建的字符串的引用地址。所以上面s1与s2引用地址相同。

    那为什么s3与s1、s2引用的不是同一个字符串地址呢?

    注意看 s3的定义方法:

    String s3=new String("Hello"); 

    JVM首先是在字符串常量池中找"Hello" 字符串,如果没有创建字符串常量,然后放到常量池中,若已存在,则不需要创建;当遇到 new 时,还会在内存(不是字符串常量池中,而是在堆里面)上创建一个新的String对象,存储"Hello",并将内存上的String对象引用地址返回,所以s3与s1、s2引用的不是同一个字符串地址。 内存结构图如下:

    从内存图可见,s1与s2指向的都是常量池中的字符串常量,所以它们比较的是同一块内存地址,而s3指向的是堆里面的一块地址,说的具体点应该是堆里面的Eden区域,s1跟s3,s2跟s3比较都是不相等的,都不是同一块地址。

    拓展问题:

    请问String s = new String("xyz");产生了几个对象?

    在String的工作原理中,已经提到了,new一个String对象,是需要先在字符串常量中查找相同值或创建一个字符串常量,然后再在内存堆中创建一个String对象,所以String s = new String("xyz"); 会创建两个对象。

    下面看几道习题:

    1、

    public class Test {  
      public static void main(String[ ] args) {
        String s1 = new String("Welcome to Java!");
        String s2 = new String("Welcome to Java!");
        if (s1 == s2)
          System.out.println("s1 and s2 reference to the same String object");
        else
          System.out.println("s1 and s2 reference to different String objects");
      }
    }

    s1 and s2 have different contents

    虽然常量池中已经存在"Welcome to Java!"了,但s2 new 时,还会在内存(不是字符串常量池中,而是在堆里面)上创建一个新的String对象,存储"Welcome to Java!",并将内存上的String对象引用地址返回给s2,所以s1和s2引用地址不同。

    2、

    public class Test {  
      public static void main(String[ ] args) {
        String s1 = "Welcome to Java!";
        String s2 = s1;
        if (s1 == s2)
          System.out.println("s1 and s2 reference to the same String object");
        else
          System.out.println("s1 and s2 reference to different String objects");
      }
    }

    s1 and s2 reference to the same String object

    常量池中已经存在"Welcome to Java!"了,不需要再创建,直接返回该字符串的引用地址给s2,所以s1和s2有相同的引用地址。

    再来看这样一个问题:

    public class Test {
        public static void main(String[] args) {
            String s1 = "hello";
            String s2 = "world";
            String s3 = "helloworld";
            System.out.println(s3 == s1 + s2);// false
            System.out.println(s3.equals((s1 + s2)));// true
            System.out.println(s3 == "hello" + "world");// ture
            System.out.println(s3.equals("hello" + "world"));// true
        }
    }

    equals()比较方法不解释,比较值,均相等,均为true。

    1. s1与s2相加是先在字符串常量池中开一个空间,然后拼接,这个空间的地址就是s1与s2拼接后的地址。与s3的地址不同,所以输出为false。
    2. s3与”hello”+”world”作比较,”hello”+”world”先拼接成”helloworld”,然后再去字符串常量池中找是否有”helloworld”,有,所以和s3共用一个字符串对象,则为true。

    总结:
    String s = new String(“hello”)会创建2(1)个对象,String s = “hello”创建1(0)个对象。
    注:当字符串常量池中有对象hello时括号内成立!
    字符串如果是变量相加,先开空间,在拼接。
    字符串如果是常量相加,是先加,然后在常量池找,如果有就直接返回,否则,就创建。

  • 相关阅读:
    gulp
    grunt
    iscroll手册
    Javascript闭包演示【转】
    【转】Backbone.js学习笔记(二)细说MVC
    【转】Backbone.js学习笔记(一)
    node包管理相关
    写出高效率的正则表达式的几点建议
    常用正则表达式
    help、man和info工具的区别
  • 原文地址:https://www.cnblogs.com/wkfvawl/p/11656137.html
Copyright © 2011-2022 走看看