String s = new String("java"); 只创建了一个对象!好好看好好学,要了解原理!

简介: String s = new String("java"); 只创建了一个对象!好好看好好学,要了解原理!
public static void main(String[] args) {
    String str1 = new StringBuilder("计算机").append("软件").toString();
    System.out.println(str1.intern() == str1);

    String str2 = new StringBuilder("ja").append("va").toString();
    System.out.println(str2.intern() == str2);
}

这个题目是在《深入理解Java虚拟机:JVM高级特性与实战(第3版)》看到的,按理说这两个结果不应该一样吗?为什么会出这种题呢?

640.jpg
640-1.jpg

作者想靠诉我,一次不信,两次你应该信了吧!机智如我。为了证明我如此机智,我特地的试了一下。

640.png

额,应该我看错了,再来亿遍。。。我的idea肯定出问题了,让同事跑一下试试!

640.jpg

为什么?为什么?为什么?你要离开我!(不好意思串台了)。为什么是true和flase。

640.jpg

吧啦吧啦吧啦说了一大堆,意思就是想让读者知道,字符串常量池jdk1.6和jdk1.7及以上存放的位置变啦,以前放到永久代的,以后就放在java堆上了。jdk1.6的intern()的方法首次遇到会把字符串复制一份到有永久代,而jdk1.7及以上的只需要在常量池里记录一下首次出现的实例引用。"只需要在常量池里记录一下首次出现的实例引用"说白了就是常量池记录第一次出现这个字符串的地址。其实我这地方有个好奇,那不就是这个对象永久不会被垃圾收集器收集了嘛?当然我也不敢问。。。

既然都说到这了,那就一起看看intern()方法吧!(jdk1.8)

640.jpg

/**
    * Returns a canonical representation for the string object.
    * <p>
    * A pool of strings, initially empty, is maintained privately by the
    * class {@code String}.
    * <p>
    * When the intern method is invoked, if the pool already contains a
    * string equal to this {@code String} object as determined by
    * the {@link #equals(Object)} method, then the string from the pool is
    * returned. Otherwise, this {@code String} object is added to the
    * pool and a reference to this {@code String} object is returned.
    * <p>
    * It follows that for any two strings {@code s} and {@code t},
    * {@code s.intern() == t.intern()} is {@code true}
    * if and only if {@code s.equals(t)} is {@code true}.
    * <p>
    * All literal strings and string-valued constant expressions are
    * interned. String literals are defined in section 3.10.5 of the
    * <cite>The Java&trade; Language Specification</cite>.
    *
    * @return  a string that has the same contents as this string, but is
    *          guaranteed to be from a pool of unique strings.
    */
public native String intern();

原谅我看不懂,所以谷歌翻译了下。其实意思就是调用intern方法时,如果池中已经包含一个等于此对象的字符串,此方法,则从池中取出字符串返回。否则,此对象地址将添加到池,并返回对此对象的引用。 额,和上面一个意思。

叽叽歪歪说了半天,我知道第一个是true,我是问你第二个为什么是false,光说屁话。

640.jpg

老爷们别生气,我这就慢慢给你道来。其实我也不知道。然后在知乎看到一片文章《如何理解《深入理解java虚拟机》第二版中对String.intern()方法的讲解中所举的例子?》,呵呵哒,原来在初始化的时候已经把java这个字符串放到常量池中了。

640.jpg

你说这不巧了吗?

640.jpg

举个例子让我怀疑了人生,哎。。。
哎,别先,如果我发现了一个面试题,String s = new String("s")证明他是创建两个对象的了,哈哈哈哈。。。

640-1.jpg

public static void main(String[] args) {
    String s = new String("s");
    System.out.println(s.intern() == s);
}

结果是false,那不就是创建了两个对象吗?第一个是new String("s"),第二个是常量池的s。哈哈哈哈。
小编小编,那你怎么证明java启动的时候常量池里面没有s呢?毕竟java这个字符串一开始也存在常量池啊!
额。。。

640.jpg

我又想到一个有意思的问题,String s = new String("java")创建了几个对象,哈哈哈哈,它创建了一个对象,这次没人反驳我了把。哈哈哈哈~

相关文章
|
2月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
294 0
|
2月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
294 5
|
4月前
|
缓存 安全 Java
Java反射机制:动态操作类与对象
Java反射机制是运行时动态操作类与对象的强大工具,支持获取类信息、动态创建实例、调用方法、访问字段等。它在框架开发、依赖注入、动态代理等方面有广泛应用,但也存在性能开销和安全风险。本文详解反射核心API、实战案例及性能优化策略,助你掌握Java动态编程精髓。
|
4月前
|
存储 SQL 缓存
Java字符串处理:String、StringBuilder与StringBuffer
本文深入解析Java中String、StringBuilder和StringBuffer的核心区别与使用场景。涵盖字符串不可变性、常量池、intern方法、可变字符串构建器的扩容机制及线程安全实现。通过性能测试对比三者差异,并提供最佳实践与高频面试问题解析,助你掌握Java字符串处理精髓。
|
4月前
|
存储 人工智能 JavaScript
Java从作用域到对象高级应用​
本内容详细讲解了JavaScript中的作用域类型(函数作用域、块作用域、全局作用域)、作用域链、垃圾回收机制、闭包、变量提升、函数参数、数组方法、内置构造函数、对象高级知识、原型链、对象赋值、深浅拷贝、递归、异常处理及this指向等内容,全面覆盖JS核心概念与编程技巧。
57 0
|
5月前
|
监控 Java API
现代 Java IO 高性能实践从原理到落地的高效实现路径与实战指南
本文深入解析现代Java高性能IO实践,涵盖异步非阻塞IO、操作系统优化、大文件处理、响应式网络编程与数据库访问,结合Netty、Reactor等技术落地高并发应用,助力构建高效可扩展的IO系统。
155 0
|
5月前
|
存储 Java
Java对象的内存布局
在HotSpot虚拟机中,Java对象的内存布局分为三部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。对象头包含Mark Word、Class对象指针及数组长度;实例数据存储对象的实际字段内容;对齐填充用于确保对象大小为8字节的整数倍。
108 0
|
5月前
|
存储 缓存 安全
深入讲解 Java 并发编程核心原理与应用案例
本教程全面讲解Java并发编程,涵盖并发基础、线程安全、同步机制、并发工具类、线程池及实际应用案例,助你掌握多线程开发核心技术,提升程序性能与响应能力。
233 0
|
5月前
|
自然语言处理 Java Apache
在Java中将String字符串转换为算术表达式并计算
具体的实现逻辑需要填写在 `Tokenizer`和 `ExpressionParser`类中,这里只提供了大概的框架。在实际实现时 `Tokenizer`应该提供分词逻辑,把输入的字符串转换成Token序列。而 `ExpressionParser`应当通过递归下降的方式依次解析
346 14