《我要进大厂》- Java基础夺命连环14问,你能坚持到第几问?(Object类 | String类)(二)

简介: 《我要进大厂》- Java基础夺命连环14问,你能坚持到第几问?(Object类 | String类)

4、String#equals() 和 Object#equals() 有何区别?

String 中的 equals 方法是被重写过的,比较的是 String 字符串的值是否相等。 Objectequals 方法是比较的对象的内存地址。

5、字符串常量池的作用了解吗?

字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。

// 在堆中创建字符串对象”ab“
// 将字符串对象”ab“的引用保存在字符串常量池中
String aa = "ab";
// 直接返回字符串常量池中字符串对象”ab“的引用
String bb = "ab";
System.out.println(aa==bb);// true


更多关于字符串常量池的介绍可以看一下 Java 内存区域详解 这篇文章。

6、String s1 = new String(“abc”);这句话创建了几个字符串对象?


会创建 1 或 2 个字符串对象。

1、如果字符串常量池中不存在字符串对象“abc”的引用,那么会在堆中创建 2 个字符串对象“abc”。

示例代码(JDK 1.8):

String s1 = new String("abc");


对应的字节码:


7244bdaea01aab2db40019597b2a5de4.png


ldc 命令用于判断字符串常量池中是否保存了对应的字符串对象的引用,如果保存了的话直接返回,如果没有保存的话,会在堆中创建对应的字符串对象并将该字符串对象的引用保存到字符串常量池中。


2、如果字符串常量池中已存在字符串对象“abc”的引用,则只会在堆中创建 1 个字符串对象“abc”。


示例代码(JDK 1.8):

// 字符串常量池中已存在字符串对象“abc”的引用
String s1 = "abc";
// 下面这段代码只会在堆中创建 1 个字符串对象“abc”
String s2 = new String("abc");


对应的字节码:


f54991040758e643f976615666d9feef.png


这里就不对上面的字节码进行详细注释了,7 这个位置的 ldc 命令不会在堆中创建新的字符串对象“abc”,这是因为 0 这个位置已经执行了一次 ldc 命令,已经在堆中创建过一次字符串对象“abc”了。7 这个位置执行 ldc 命令会直接返回字符串常量池中字符串对象“abc”对应的引用。


7、intern 方法有什么作用?


String.intern() 是一个 native(本地)方法,其作用是将指定的字符串对象的引用保存在字符串常量池中,可以简单分为两种情况:


如果字符串常量池中保存了对应的字符串对象的引用,就直接返回该引用。

如果字符串常量池中没有保存了对应的字符串对象的引用,那就在常量池中创建一个指向该字符串对象的引用并返回。

示例代码(JDK 1.8) :

// 在堆中创建字符串对象”Java“
// 将字符串对象”Java“的引用保存在字符串常量池中
String s1 = "Java";
// 直接返回字符串常量池中字符串对象”Java“对应的引用
String s2 = s1.intern();
// 会在堆中在单独创建一个字符串对象
String s3 = new String("Java");
// 直接返回字符串常量池中字符串对象”Java“对应的引用
String s4 = s3.intern();
// s1 和 s2 指向的是堆中的同一个对象
System.out.println(s1 == s2); // true
// s3 和 s4 指向的是堆中不同的对象
System.out.println(s3 == s4); // false
// s1 和 s4 指向的是堆中的同一个对象
System.out.println(s1 == s4); //true

8、String 类型的变量和常量做“+”运算时发生了什么?

先来看字符串不加 final 关键字拼接的情况(JDK1.8):

String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
String str5 = "string";
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false

注意 :比较 String 字符串的值是否相等,可以使用 equals() 方法。 String 中的 equals 方法是被重写过的。 Object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是字符串的值是否相等。如果你使用 == 比较两个字符串是否相等的话,IDEA 还是提示你使用 equals() 方法替换。


befc5b594e1a3f1bf50246132f2e3e85.png

对于编译期可以确定值的字符串,也就是常量字符串 ,jvm 会将其存入字符串常量池。并且,字符串常量拼接得到的字符串常量在编译阶段就已经被存放字符串常量池,这个得益于编译器的优化。


在编译过程中,Javac 编译器(下文中统称为编译器)会进行一个叫做 常量折叠(Constant Folding) 的代码优化。《深入理解 Java 虚拟机》中是也有介绍到:


3a49530e7f55698829406a1378ba3220.png

常量折叠会把常量表达式的值求出来作为常量嵌在最终生成的代码中,这是 Javac 编译器会对源代码做的极少量优化措施之一(代码优化几乎都在即时编译器中进行)。


对于 String str3 = "str" + "ing"; 编译器会给你优化成 String str3 = "string"; 。


并不是所有的常量都会进行折叠,只有编译器在程序编译期就可以确定值的常量才可以:


基本数据类型( byte、boolean、short、char、int、float、long、double)以及字符串常量。

final 修饰的基本数据类型和字符串变量

字符串通过 “+”拼接得到的字符串、基本数据类型之间算数运算(加减乘除)、基本数据类型的位运算(<<、>>、>>> )

引用的值在程序编译期是无法确定的,编译器无法对其进行优化。


对象引用和“+”的字符串拼接方式,实际上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象 。


String str4 = new StringBuilder().append(str1).append(str2).toString();

我们在平时写代码的时候,尽量避免多个字符串对象拼接,因为这样会重新创建对象。如果需要改变字符串的话,可以使用 StringBuilder 或者 StringBuffer

不过,字符串使用 final 关键字声明之后,可以让编译器当做常量来处理。

示例代码:

final String str1 = "str";
final String str2 = "ing";
// 下面两个表达式其实是等价的
String c = "str" + "ing";// 常量池中的对象
String d = str1 + str2; // 常量池中的对象
System.out.println(c == d);// true

被 final 关键字修改之后的 String 会被编译器当做常量来处理,编译器在程序编译期就可以确定它的值,其效果就相当于访问常量。

如果 ,编译器在运行时才能知道其确切值的话,就无法对其优化。

示例代码(str2 在运行时才能确定其值):

final String str1 = "str";
final String str2 = getStr();
String c = "str" + "ing";// 常量池中的对象
String d = str1 + str2; // 在堆上创建的新的对象
System.out.println(c == d);// false
public static String getStr() {
      return "ing";
}

总结

OK,今天关于Java常见类之Object、String的总结就到这里的,希望本篇文章能够帮助到大家,同时也希望大家看后能学有所获!!!

好了,我们下期见~

相关文章
|
8天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
35 17
|
4天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
31 4
|
5天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
12 2
|
9天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
13天前
|
存储 Java 编译器
java wrapper是什么类
【10月更文挑战第16天】
20 3
|
6月前
|
安全 Java
Java StringBuffer 和 StringBuilder 类
Java StringBuffer 和 StringBuilder 类
46 0
|
3月前
|
安全 Java API
Java系类 之 String、StringBuffer和StringBuilder类的区别
这篇文章讨论了Java中`String`、`StringBuffer`和`StringBuilder`三个类的区别,其中`String`是不可变的,而`StringBuffer`是线程安全的可变字符串类,`StringBuilder`是非线程安全的可变字符串类,通常在单线程环境下性能更优。
Java系类 之 String、StringBuffer和StringBuilder类的区别
|
3月前
|
安全 Java
【Java基础面试二十七】、说一说StringBuffer和StringBuilder有什么区别
这篇文章介绍了Java中StringBuffer和StringBuilder的区别:StringBuffer是线程安全的,而StringBuilder是非线程安全的,因此在单线程环境下优先推荐使用StringBuilder以获得更好的性能。
|
3月前
|
API C# 开发者
WPF图形绘制大师指南:GDI+与Direct2D完美融合,带你玩转高性能图形处理秘籍!
【8月更文挑战第31天】GDI+与Direct2D的结合为WPF图形绘制提供了强大的工具集。通过合理地使用这两种技术,开发者可以创造出性能优异且视觉效果丰富的WPF应用程序。在实际应用中,开发者应根据项目需求和技术背景,权衡利弊,选择最合适的技术方案。
130 0
|
6月前
|
存储 Java
Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究
Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究
Java基础复习(DayThree):字符串基础与StringBuffer、StringBuilder源码研究
下一篇
无影云桌面