今天课堂测试做了几道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时括号内成立!
字符串如果是变量相加,先开空间,在拼接。
字符串如果是常量相加,是先加,然后在常量池找,如果有就直接返回,否则,就创建。

Java中String直接赋字符串和new String的一些问题的更多相关文章

  1. Java中String直接赋字符串和new String的区别

    解析Java中的String对象的数据类型 1. String是一个对象.  因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ...

  2. Java中String直接赋字符串和new String的区别(面试常考)

    摘取自:https://www.cnblogs.com/guozhenqiang/p/5633269.html 解析Java中的String对象的数据类型 1. String是一个对象.  因为对象的 ...

  3. Java中String直接赋字符串和new String的区别 如String str=new String("a")和String str = "a"有什么区别?

    百度的面试官问 String A="ABC"; String B=new String("ABC"); 这两个值,A,B 是否相等,如果都往HashSet里面放 ...

  4. String直接赋字符串和new String的区别

    String A="ABC"; String B=new String("ABC"); String A = "ABC";内存会去查找常量池 ...

  5. JAVA中令人疑惑的字符串

    Java中不同的字符串存在于同一个存储池中,字符串变量将指向存储池中相应的位置,也就是字符串变量里面包含的并不是字符串而是这个字符串对象的内存地址. String a = "123" ...

  6. Java 中 常用API概述之 Math, Object, String,StringBuffer类,Arrays,Integer类

    Math Math类包含执行基本数字运算的方法,如基本指数,对数,平方根和三角函数. 与StrictMath类的一些数字方法不同,Math类的StrictMath所有Math都没有定义为返回比特位相同 ...

  7. Java中XML格式的字符串4读取方式的简单比较

    Java中XML格式的字符串4读取方式的简单比较 1.java自带的DOM解析. import java.io.StringReader; import javax.xml.parsers.Docum ...

  8. 使用java中replaceAll方法替换字符串中的反斜杠

    今天在项目中使用java中replaceAll方法将字符串中的反斜杠("\")替换成空字符串(""),结果出现如下的异常: java.util.regex.Pa ...

  9. Java中各种集合(字符串类)的线程安全性!!!

    Java中各种集合(字符串类)的线程安全性!!! 一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读 ...

随机推荐

  1. 《Java基础知识》Java内部类及其实例化

    在 Java 中,允许在一个类(或方法.语句块)的内部定义另一个类,称为内部类(Inner Class),有时也称为嵌套类(Nested Class). 内部类和外层封装它的类之间存在逻辑上的所属关系 ...

  2. Dynamics 365 Portal 修改注册页面及Profile页面

    一,Profile页面 客户要求在Portal Profile页面上添加性别字段,通过查看源代码发现,中间的联系人信息部分是引用的CRM中Contact实体的Portal Web Form表单,直接把 ...

  3. 微信小程序—支付宝小程序与微信小程序的不同点对比

    支付宝小程序语法 http://caibaojian.com/aliapp-wxapp.html https://www.cnblogs.com/bgwhite/p/9447639.html http ...

  4. Linux中环境变量相关文件的区别

    Linux下各种不同环境变量相关文件的作用: 1. /etc/environment  设置整个系统的环境,系统启动时,该文件被执行. 2. /etc/profile     设置所有用户的环境,当用 ...

  5. 初级模拟电路:4-3 BJT晶体管的交流建模

    回到目录 1. 四种BJT模型概述 对BJT晶体管建模的基本思路就是,用电路原理中的五大基本元件(电阻.电容.电感.电源.受控源)构建一个电路,使其在一定工作条件下能等效非线性半导体器件的实际工作.一 ...

  6. Java并发的若干基本陷阱、原理及解决方案

    勿止于结论:持续探索与求证. 概述 为什么要使用并发 ? 有三点足够信服的理由: 性能提升.单核 CPU 的性能基本抵达瓶颈,充分挖掘多核 CPU 的能力,使得性能提升变成水平可扩展的. 事件本质.世 ...

  7. 最后的记忆——Spring ApplicationContext

    本文尝试分析一下Spring 的 ApplicationContext体系的 接口设计,尝试理解为什么这么做,为什么接口这么设计.为什么这么去实现,为什么需要有这个方法,为什么 这样命名?接口.类.方 ...

  8. Java方法之重载

    Java方法之重载 本篇探究Java中的方法重载.那么,什么是重载呢?先上一串代码: package com.my.pac06; /** * @author Summerday * @date 201 ...

  9. 使用matplotlib库绘制函数图

    函数如下: z = x^2 * y / (x^4 +y^2) 代码如下: import numpy as np import matplotlib.pyplot as plt import mpl_t ...

  10. 海康Poe 摄像头尾线与8根网线连接方法

    家里海康POE摄像头铜丝断了一根,拆开自己接了个RJ44座,线序黑. 棕. 绿. 橙. 红. 黄. 紫. 蓝 以此 对应橙白.橙.绿白.蓝.蓝白.绿.棕白.棕经测试无误,可以正常使用