一、创建String
创建一个String对象,主要有两种方式:
- String s=”Hello world!”;
- String s=new String(“Hello world”);
两种方式虽然都实现了创建一个String对象的功能,但实现的原理却大不相同。在讨论这两种方法的不同之前,我们先来了解一下JVM里的常量池概念,对接下来的理解很有帮助。
相信大家都知道,Java程序在运行之前,编译器首先要把源代码编译成字节码文件(.class文件),然后JVM再解释执行.class文件。其中,在.class文件中有一个非常重要的项—常量池,我们上面代码中的”Hello world”字符串被编译之后,就被存放在class常量池中的字符串常量表中。改用网上一段话:
在Java源代码中的每一个字面值字符串,都会在编译成class文件阶段,形成标志号 为8(CONSTANT_String_info)的常量表 。 当JVM加载 class文件的时候,会为对应的常量池建立一个内存数据结构,并存放在方法区中。同时JVM会自动为CONSTANT_String_info常量表中 的字符串常量字面值 在堆中创建 新的String对象(intern字符串对象)。然后把CONSTANT_String_info常量表的入口地址转变成这个堆中String对象的直接地址(常量池解析)。
源代码中所有相同字面值的字符串常量只可能建立唯一一个intern字符串对象。另外,我们也可以调用String的intern()方法来使得一个常规字符串对象成为intern字符串对象。
好了,下面我们来讨论一下第一种方法,也是大家非常常用的方法:
String s=”Hello world!”
首先在编译期,也就是在运行这段指令之前,JVM就已经为”Hello world”在堆中创建了一个intern字符串,局部变量s存储的是早已创建好的intern字符串的堆地址。也就是说,不管有几条String s1=”Hello world”,堆中都只有1个值为”Hello world”的字符串。
那么第二种方法呢?
String s=new String(“Hello world”)
同样在编译期,JVM也为”Hello world”在堆中创建了一个intern字符串,然后用这个intern字符串的值来初始化new出来的新String对象,局部变量s实际上存储的是new出来的堆对象地址。 此时在JVM管理的堆中,有两个相同字符串值的String对象:一个是intern字符串对象,一个是new新建的字符串对象。
最后,来段代码做个更形象的比较:
//代码1
String sa = "ab";
String sb = "cd";
String sab=sa+sb;
String s="abcd";
System.out.println(sab==s); // false
//代码2
String sc="ab"+"cd";
String sd="abcd";
System.out.println(sc==sd); //true
代码1中局部变量sa,sb存储的是堆中两个intern字符串对象的地址。而当执行sa+sb时,JVM首先会在堆中创建一个StringBuilder类,同时用sa指向的intern字符串对象完成初始化,然后调用append方法完成对sb所指向的intern字符串的合并操作,接着调用StringBuilder的toString()方法在堆中创建一个String对象,最后将刚生成的String对象的堆地址存放在局部变量sab中。而局部变量s存储的是常量池中”abcd”所对应的intern字符串对象的地址。 sab与s地址当然不一样了。这里要注意了,代码1的堆中实际上有五个字符串对象:三个intern字符串对象、一个String对象和一个StringBuilder对象。
代码2中”ab”+”cd”会直接在编译期就合并成常量”abcd”, 因此相同字面值常量”abcd”所对应的是同一个拘留字符串对象,自然地址也就相同。
二、String,StringBuffer和StringBuilder
分享到:
相关推荐
### 性能飞跃的催化剂:揭秘Java JIT编译器的魔法 #### Java语言概览 Java自1995年由Sun Microsystems(现归于Oracle旗下)首次推出以来,迅速成为了软件开发领域的重要语言之一。其面向对象的设计理念,强调通过...
### 揭秘控制流的秘密:Java中的if, for, while 在编程的世界里,控制流语句犹如导航灯塔,指引着程序前进的方向。本文将深入解析Java中的三种核心控制流语句——if、for、while及其变体,并通过具体的实例帮助读者...
### 揭秘Spring的魔力:Spring框架在Java开发中的核心作用 #### Java的主要特点及其应用领域 Java作为一门广泛使用的编程语言,自1995年由Sun Microsystems首次发布以来,已经成为众多领域的首选语言之一。Java的...
Java面试题大揭秘 Java是一种广泛使用的编程语言,Java面试题涵盖了Java语言的方方面面,本文将对Java面试题中的知识点进行系统的总结和解释。 一、Java并发编程 Java并发编程是指在Java程序中处理多个线程并行...
│ Java面试题08.String.mp4 │ Java面试题09.讲一下java中的集合.mp4 │ Java面试题10.ArrayList LinkedList.mp4 │ Java面试题11.HashMap和HashTable的区别.mp4 │ Java面试题12.实现一个拷贝文件的类使用字节流...
在Java中,我们可以使用`java.security.MessageDigest`类来实现这个过程。首先创建一个MessageDigest实例,然后用它对签名字符串进行哈希,最后获取哈希结果。例如,使用SHA-256算法的代码片段可能如下: ```java ...
在这个例子中,构造函数`Car(String make, String model, int year)`接受三个参数,并将其分别赋值给类中的私有变量。通过这种方式,我们在创建`Car`对象时就可以传递具体的值,实现对新对象的初始化。 #### 第二章...
以下是书中涵盖的一些关键知识点: 1. **Java内存模型与垃圾收集**: - 解析Java内存模型(JMM),包括堆内存、栈内存、方法区以及本地方法栈等,以及它们如何影响性能。 - 垃圾收集机制的工作原理,如标记-清除...
Kotlin,由JetBrains公司开发,是一种现代、静态类型的编程语言,主要用于Java虚拟机(JVM)以及Android平台。自2017年被Google宣布为Android开发的首选语言以来,Kotlin在移动开发领域迅速崛起,并在全栈开发中也...
Java中如何使用多线程处理并发任务。 - **服务器协议** 多线程在服务器端的应用,例如处理多个客户端的请求。 - **一客户一线程** 为每个客户端分配一个单独的线程进行处理。 - **线程池** 使用线程池管理...
异或运算符(^)是Java语言中的一个二元运算符,它可以对两个数值进行异或运算。异或运算的原理是,如果一个字符(或数值)A与一个数值B进行异或运算得到C,则再用C和B进行异或运算就可以还原得到A。这是因为异或...
#### 第12天~第13天:Java中的异常和包的使用 1. **异常处理**: - 异常的概念及其分类:编译时异常、运行时异常。 - try-catch-finally语句块。 - 自定义异常。 - 异常链:throwable.getCause()。 2. **包的...
在《GWT揭秘》一书的8.1节中,详细讲解了如何在GWT中使用XMLHttpRequest来请求动态数据。本篇文章将深入探讨这一主题。 首先,XMLHttpRequest是Web开发中的一个基础组件,它允许浏览器在不刷新整个页面的情况下向...
MyBatis查询语句揭秘之参数解析 MyBatis是一种流行的Java持久层框架,它提供了强大的查询功能。其中,参数解析是MyBatis查询语句中不可或缺的一部分。本文将深入探讨MyBatis查询语句中的参数解析机制,涵盖参数的...
根据提供的文件信息,“C++黑客编程揭秘与防范 第2版.pdf”,我们可以推断这本书主要聚焦于C++语言在黑客攻击中的应用以及相应的防范措施。尽管给出的信息非常有限,但基于书名及其描述,我们可以深入探讨以下几个...
Mybatis核心组成部分之SQL映射文件揭秘详解 Mybatis是一个基于Java的持久层框架,它的核心...通过这个实例,我们可以看到Mybatis的强大功能,它可以自动地将数据库结果集映射到Java对象中,方便了数据的处理和使用。
在这个项目中,作者将分享自己对Java源代码的个人理解和分析,使其他开发者也能从中受益。 在Java的世界里,源代码分析是一项重要的学习环节,它有助于我们理解JVM(Java虚拟机)如何执行代码,以及Java类库的各种...
### Java Puzzlers知识点解析 ...以上就是对《JavaSIG-Puzzlers.pdf》中“A Big Delight in Every Byte”谜题的详细解析,希望能够帮助开发者更好地理解Java中的类型转换机制,从而编写更加健壮的代码。