在研究String直接赋值与new String的区别之前我们需要先了解java中的字符串常量池的概念

字符串常量池

String类是我们平常项目中使用频率非常高的一种对象类型,jvm为了提升性能和减少内存开销,避免字符的重复创建,其维护了一块特殊的内存空间,即字符串池,当需要使用字符串时,先去字符串池中查看该字符串是否已经存在,如果存在,则可以直接使用,如果不存在,初始化,并将该字符串放入字符创常量池中。

使用String直接赋值

String str = “abc”;可能创建一个或者不创建对象,如果”abc”在字符串池中不存在,会在java字符串池中创建一个String对象(”abc”),然后str指向这个内存地址,无论以后用这种方式创建多少个值为”abc”的字符串对象,始终只有一个内存地址被分配。==判断的是对象的内存地址,而equals判断的是对象内容。通过以下代码测试:

String str = "abc";
String str1 = "abc";
String str2 = "abc";
System.out.println(str==str1);//true
System.out.println(str==str2);//true
也就是str、str1、str2都是指向同一个内存地址。

使用new String 创建字符串

String str = new String(“abc”);至少会创建一个对象,也有可能创建两个。因为用到new关键字,肯定会在堆中创建一个String对象,如果字符池中已经存在”abc”,则不会在字符串池中创建一个String对象,如果不存在,则会在字符串常量池中也创建一个对象。

String str = new String("abc");
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str==str1);//false
System.out.println(str==str2);//false

可以看出来,str、str1、str2指向的是不同的内存地址

        这里解释一下,对于通过 new 产生一个字符串(假设为 ”china” )时,会先去常量池中查找是否已经有了 ”china” 对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此 ”china” 对象的拷贝对象。

使用String拼接字符串

项目中除了直接使用=赋值,也会用到字符串拼接,字符串拼接又分为变量拼接和已知字符串拼接

String str = "abc";//在常量池中创建abc
String str1 = "abcd";//在常量池中创建abcd
String str2 = str+"d";//拼接字符串,此时会在堆中新建一个abcd的对象,因为str2编译之前是未知的
String str3 = "abc"+"d";//拼接之后str3还是abcd,所以还是会指向字符串常量池的内存地址
System.out.println(str1==str2);//false
System.out.println(str1==str3);//true

str和str1都是字符串常量所以在编译期就被确定了!而str2中有个str是引用不是字符串常量所以不会在编译期确定。

而String是final的!所以在b+"c"的时候实际上是新创建了一个对象,然后在把新创建对象的引用传给c.

所以在项目中还是不要使用new String去创建字符串,最好使用String直接赋值。

String 有一个intern() 方法,native,用来检测在String pool是否已经有这个String存在。

 
public String intern()
  返回字符串对象的规范化表示形式。
  一个初始时为空的字符串池,它由类 String 私有地维护。当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。所有字面值字符串和字符串赋值常量表达式都是内部的。
返回:一个字符串,内容与此字符串相同,但它保证来自字符串池中。
考虑下面的问题:
public static void main(String[] args) throws Exception {
String a = "b" ;
String b = "b" ; System.out.println( a == b); //true
String d = new String( "d" ).intern() ;
String c = "d" ;
System.out.println( c == d); //true System.out.println("------------------"); String d1 = new String( "d" ) ;
String e1=d1.intern();
String c1 = "d" ;
System.out.println( c1 == d1); //false
System.out.println( c1 == e1); //true
System.out.println( e1 == d1); //false System.out.println("------------------"); String s1=new String("kvill");
String s2=s1.intern();
System.out.println( s1==s2 ); //false
System.out.println( s1+" "+s2 ); //kvill kvill
System.out.println( s2==s1.intern() ); //true }

面试题:

String s = new String(“xyz”); 产生几个对象?

         一个或两个。如果常量池中原来没有 ”xyz”, 就是两个。如果原来的常量池中存在“xyz”时,就是一个。对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。

java中String new和直接赋值的区别

    对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
 
 

String直接赋值与使用new String的区别的更多相关文章

  1. String new赋值、直接赋值

    String类是final的.String str = new String("Hello"); //创建了两个对象系统会先创建一个匿名对象"Hello"存入堆 ...

  2. C风格字符串和C++ string 对象赋值操作的性能比较

    <<C++ Primer>> 第四版 Exercise Section 4.3.1 部分Exercise 4.2.9 习题如下: 在自己本机执行如下程序,记录程序执行时间: # ...

  3. 第01篇 为什么推荐使用String直接赋值

    在四海学的时候,可能需要我们经过沉淀才会去想一些事情,有的时候不知道为什么这样或者那样的时候,从今天看是,胖先生打算给大家开辟一个课程,就是我的读书笔记. 首先我们来认识一下String字符串 一般对 ...

  4. String在方法中的传递方式(调用外部方法给String变量赋值时,未得到预期结果)

    示例: public class StringTraining { public static void changeStr(String str){ str = "137878" ...

  5. string的赋值

    string的赋值 string s1="123456"; 一:     只能在刚开始定义的时候用: (1)     从后往前赋值     string s2(s1,3);     ...

  6. 用new关键字对一个String 变量赋值和用literal值直接赋值有什么不同(转)

    String str1="ABC": 和String str2 = new String("ABC"); 有什么区别. String str1="AB ...

  7. String的内存模型,为什么String被设计成不可变的

    String是Java中最常用的类,是不可变的(Immutable), 那么String是如何实现Immutable呢,String为什么要设计成不可变呢? 前言 关于String,收集一波基础,来源 ...

  8. CodeForces 632C The Smallest String Concatenation//用string和sort就好了&&string的基础用法

    Description You're given a list of n strings a1, a2, ..., an. You'd like to concatenate them togethe ...

  9. String、StringBuffer、StringBuilder和StringTokenizer的区别

    1)String.StringBuffer.StringBuilder都用于字符串操作,其中,String是不可变类,即String对象一旦被创建,其值不能被修改,而StringBuffer和Stri ...

随机推荐

  1. 基于大量图片与实例深度解析Netty中的核心组件

    本篇文章主要详细分析Netty中的核心组件. 启动器Bootstrap和ServerBootstrap作为Netty构建客户端和服务端的路口,是编写Netty网络程序的第一步.它可以让我们把Netty ...

  2. springboot利用mock进行junit单元测试,测试controller

    1  spring-boot-starter-test内置mockito,添加pom依赖 <dependency> <groupId>org.springframework.b ...

  3. Django 小实例S1 简易学生选课管理系统 4 实现登录页面

    Django 小实例S1 简易学生选课管理系统 第4节--实现登录页面 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 本文涉及到的新的额外知识点: ...

  4. excel (2)

    ... poi 3.8 import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; ...

  5. 【Python】300行代码搞定HTML模板渲染

    一.前言 模板语言由HTML代码和逻辑控制代码组成,此处@PHP.通过模板语言可以快速的生成预想的HTML页面.应该算是后端渲染不可缺少的组成部分. 二.功能介绍 通过使用学习tornado.bott ...

  6. BootStrap中模态框踩坑

    在模态框中使用html标签上的自定义属性来打开模态框后,在使用JS关闭模态框,就会出现多层蒙板问题 出现这个问题的原因就是没有仔细看bootstrap的官方文档,我人麻了,搞了好久 务必将模态框的 H ...

  7. 跟着老猫来搞GO-内建容器Map

    前期回顾 在上面的文章中,老猫和大家分享了GO语言中比较重要的两种数据结构,一种是数组,另外一种是基于数组的slice.本篇文章想要继续和大家分享剩下的容器以及字符字符串的处理. MAP map的定义 ...

  8. 学习 NPM 最基础的指令

    什么是 NPM npm的核心是一个软件注册表(software registry). registry /ˈredʒɪstri/ n. 注册表:登记处:挂号处.注册表就像是信息登记表或者数据库. np ...

  9. Java设计模式之(十)——组合模式

    1.什么是组合模式? Compose objects into tree structures to represent part-whole hierarchies.Composite lets c ...

  10. Docker容器基础入门认知-网络篇

    这篇文章中,会从 docker 中的单机中的 netns 到 veth,再到单机多个容器之间的 bridge 网络交互,最后到跨主机容器之间的 nat 和 vxlan 通信过程,让大家对 docker ...