热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于String如何创建对象

1.先简单看一看JVM内存结构方法区:该区为各个线程共享,用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译出来的代码等数据。常量池就在这
1.先简单看一看JVM内存结构

<br>
方法区&#xff1a; 该区为各个线程共享&#xff0c;用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译出来的代码等数据。
常量池就在这个区域

堆&#xff1a; Heap区被所有的线程共享&#xff0c;在虚拟机启动时创建。此区的功能就是存放对象实例&#xff0c;几乎所有的对象实例都是在这里分配内容。Heap区垃圾回收器管理的主要区域。

2.创建字符串对象

public class TestDemo {public static void main(String[] args) {String a &#61; "1";String b &#61; "1";String c &#61; b;System.out.println(a &#61;&#61; b);System.out.println(c &#61;&#61; b);String d &#61; new String("test");String e &#61; new String("1");String f &#61; new String(a);System.out.println(d &#61;&#61; a);System.out.println(e &#61;&#61; d);String g &#61; "hello" &#43; "tomorrow";String h &#61; new String("hello") &#43; new String("world");}
}

首先&#xff0c;看一下

String a &#61; "1";String b &#61; "1";String c &#61; b;System.out.println(a &#61;&#61; b);System.out.println(c &#61;&#61; b);

<br>
控制台返回 true

分析上述代码的输出结果&#xff1a; 上述代码&#xff0c;只创建了一个对象

  • 首先&#xff0c;jvm在编译阶段会判断方法区常量池中是否有 “1” 这个常量对象&#xff08;String a &#61; "1";&#xff09;
    如果有&#xff0c;a直接指向这个常量的引用
    如果没有&#xff0c;就在常量池里创建这个常量对象
  • 此过程并没有在堆中创建对象
  • String b &#61; "1"; 直接将 常量对象"1" 的地址交给了b&#xff0c;String c &#61; b; 将 b 指向的 常量对象"1" 的地址交给了c
  • 当使用&#61;&#61;判断时&#xff0c;都是在对比 常量池中的 常量对象"1" 的地址&#xff0c;故而相同&#xff0c;返回true


接着来看看

String d &#61; new String("test");

分析&#xff1a; 上述代码&#xff0c;创建了两个对象

  • 首先&#xff0c;jvm在编译阶段会判断方法区常量池中是否有 “test” 这个常量对象&#xff0c;没有就创建
  • 其次&#xff0c;通过 new 在 堆 中创建 String对象&#xff0c;d 指向的就是这个String对象的地址


继续看

String e &#61; new String("1");String f &#61; new String(a);System.out.println(d &#61;&#61; a);System.out.println(e &#61;&#61; d);System.out.println(e &#61;&#61; f);

<br>
控制台返回 false

分析上述代码的输出结果&#xff1a; 上述代码&#xff0c;创建了2个对象

  • 首先&#xff0c;常量池中已经有了 “1” &#xff0c;且 a 指向的也是 “1” 的地址
  • 所以&#xff0c;此过程只在堆中用new创建两个 String 对象
  • 虽然他们的字符串常量值都是 1&#xff0c;但是 e和f 指向的是两个不同的String对象的地址&#xff0c;所以返回值都为false


最后看&#xff1a;

String g &#61; "hello" &#43; "tomorrow";String h &#61; new String("hello") &#43; new String("world");

首先来分析String g &#61; "hello" &#43; "tomorrow"; 只创建了1个对象

  • jvm编译阶段过编译器优化后会把字符串常量直接合并成"hellotomorrow"&#xff0c;所以最终只在常量池中创建了一个 “hellotomorrow” 常量对象

接着来看String h &#61; new String("hello") &#43; new String("world"); 创建了6个对象

  • 首先 new 创建了一个 StringBuilder() 对象
  • 接着 h &#61; new String("hello") &#43; new String("world") 创建了 4 个对象&#xff08;和上述创建过程相同&#xff09;
  • 最终 new 创建了一个对象 String(“ab”)

3.补充

Integer m &#61; 3;//在常量池中创建一个常量对象 "3"String s &#61; m.toString(m);

注意&#xff1a; 此过程调用Object.toString()&#xff0c;并没有在常量池中创建新的对象。


推荐阅读
  • Java中不同类型的常量池(字符串常量池、Class常量池和运行时常量池)的对比与关联分析
    在研究Java虚拟机的过程中,笔者发现存在多种类型的常量池,包括字符串常量池、Class常量池和运行时常量池。通过查阅CSDN、博客园等相关资料,对这些常量池的特性、用途及其相互关系进行了详细探讨。本文将深入分析这三种常量池的差异与联系,帮助读者更好地理解Java虚拟机的内部机制。 ... [详细]
  • 本文详细解析了Java类加载系统的父子委托机制。在Java程序中,.java源代码文件编译后会生成对应的.class字节码文件,这些字节码文件需要通过类加载器(ClassLoader)进行加载。ClassLoader采用双亲委派模型,确保类的加载过程既高效又安全,避免了类的重复加载和潜在的安全风险。该机制在Java虚拟机中扮演着至关重要的角色,确保了类加载的一致性和可靠性。 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 本文介绍了在 Java 编程中遇到的一个常见错误:对象无法转换为 long 类型,并提供了详细的解决方案。 ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • Java高并发与多线程(二):线程的实现方式详解
    本文将深入探讨Java中线程的三种主要实现方式,包括继承Thread类、实现Runnable接口和实现Callable接口,并分析它们之间的异同及其应用场景。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 在Java中,当创建一个对象时,首先会为该对象的所有实例变量分配内存(前提是类已经加载),随后执行实例变量的初始化。接着,系统会按顺序执行静态初始化块、非静态初始化块以及构造器中的代码,确保对象的完整初始化。这一过程保证了对象的状态在创建时是正确且一致的。 ... [详细]
  • 本文探讨了如何利用Java代码获取当前本地操作系统中正在运行的进程列表及其详细信息。通过引入必要的包和类,开发者可以轻松地实现这一功能,为系统监控和管理提供有力支持。示例代码展示了具体实现方法,适用于需要了解系统进程状态的开发人员。 ... [详细]
  • 如何利用Java 5 Executor框架高效构建和管理线程池
    Java 5 引入了 Executor 框架,为开发人员提供了一种高效管理和构建线程池的方法。该框架通过将任务提交与任务执行分离,简化了多线程编程的复杂性。利用 Executor 框架,开发人员可以更灵活地控制线程的创建、分配和管理,从而提高服务器端应用的性能和响应能力。此外,该框架还提供了多种线程池实现,如固定线程池、缓存线程池和单线程池,以适应不同的应用场景和需求。 ... [详细]
  • 检查在所有可能的“?”替换中,给定的二进制字符串中是否出现子字符串“10”带 1 或 0 ... [详细]
  • 本文介绍了 .NET 中用于线程间通信的工具 WaitHandle 及其子类 ManualResetEvent 和 AutoResetEvent,并详细解释了线程池的概念及其在优化资源利用方面的优势。 ... [详细]
  • 在C#编程中,设计流畅的用户界面是一项重要的任务。本文分享了实现Fluent界面设计的技巧与方法,特别是通过编写领域特定语言(DSL)来简化字符串操作。我们探讨了如何在不使用`+`符号的情况下,通过方法链式调用来组合字符串,从而提高代码的可读性和维护性。文章还介绍了如何利用静态方法和扩展方法来实现这一目标,并提供了一些实用的示例代码。 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有