前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java岗大厂面试百日冲刺【Day53】— 基础篇4 (日积月累,每日三题)

Java岗大厂面试百日冲刺【Day53】— 基础篇4 (日积月累,每日三题)

作者头像
陈哈哈
发布2022-05-11 16:11:32
4010
发布2022-05-11 16:11:32
举报
文章被收录于专栏:MySQL入坑记

  大家好,我是陈哈哈,虎年第一篇,祝虎年大吉,拿个高薪!相信大家和我一样,都有一个大厂梦,作为一名资深Java选手,深知面试重要性,接下来我准备用100天时间,基于Java岗面试中的高频面试题,以每日3题的形式,带你过一遍热门面试题及恰如其分的解答。   一路走来,随着问题加深,发现不会的也愈来愈多。但底气着实足了不少,相信不少朋友和我一样,日积月累才是最有效的学习方式!想起高三时一个同学的座右铭:只有沉下去,才能浮上来。共勉(juan)。

车票

  本栏目Java开发岗高频面试题主要出自以下各技术栈:Java基础知识集合容器并发编程JVMSpring全家桶MyBatis等ORMapping框架MySQL数据库Redis缓存RabbitMQ消息队列Linux操作技巧等。

面试题1:String str与new String与有什么区别?

  要说明这两种字符创建方式的区别,首先要理解什么是常量池,常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量

  在常量池中存储字符串常量的内存空间,即字符串常量池,当需要使用字符串时,先去字符串池中查看该字符串是否已经存在,如果存在,则可以直接使用,如果不存在,初始化,并将该字符串放入字符串常量池中

常量池的位置

  • JDK1.7以前,常量池(包含字符串常量池)位于方法区
  • JDK1.7及以后,字符串常量池移入堆

常量池的作用

  • 节省内存空间:所有常量池中相同的常量具有同样的内存地址
  • 加快运行速率

1、String直接赋值(String str = “abc”;):

创建一个或不创建对象。如果“abc”在字符串池中不存在,会在java字符串池中创建一个String对象(“abc”),然后str指向这个内存地址,无论以后用这种方式创建多少个值为“abc”的字符串对象,始终只有一个内存地址被分配;如果“abc” 在字符串池中存在, str直接指向这个内存地址。

代码语言:javascript
复制
String str1 = "abc";
String str2 = "abc";
String str3 = "abc";
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true

2、使用new String创建字符串(String str = new String(“abc”);):

创建一个或两个对象。因为用到new关键字,肯定会在堆中创建一个String对象,如果字符池中已经存在”abc”,则不会在字符串池中创建一个String对象,如果不存在,则会在字符串常量池中也创建一个对象。

代码语言:javascript
复制
String str1 = new String("abc");
String str2 = new String("abc");
String str3 = new String("abc");
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//false

3、String拼接字符串:

  除了直接使用等号赋值,有时也会用到字符串拼接,字符串拼接又分为变量拼接和已知字符串拼接。

  只要拼接内容存在变量,那么该拼接后的新变量就是在堆内存中新建的一个对象实体。

代码语言:javascript
复制
String str = "abc"; 
String str1 = "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

概括为以下几点:

  1. 针对 String str="abc"String str=new String("abc"); 产生的对象,前者1或0,后者2或1,先看字符串常量池,如果字符串常量池中没有,都在常量池中创建一个,如果有,前者直接引用,后者在堆内存中还需创建一个“abc”实例对象。
  2. 对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中
  3. 为了提升jvm(JAVA虚拟机)性能和减少内存开销,避免字符的重复创建 项目中还是不要使用new String去创建字符串,最好使用String直接赋值。
  4. 关于equals()和 “= =” 对于String类简单来说,equals()就是比较两字符串的内容是否相等,如果相等返回true;而 “= =” 是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用,如果是返回true。

面试题2:为什么 String 在 Java 中是不可变(final)的?

  我们先来看一下String类在源码中的成员变量;在JDK1.7中,String类的主要成员变量主要为以下两个:

代码语言:javascript
复制
public final class String implements java.io.Serializable, Comparable<string>, CharSequence {

    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0</string>

  由以上的代码可以看出, 在 Java 中,String 类其实就是对字符数组char []的封装。在JDK7中,只有一个 value 变量,也就是 value 中的所有字符都是属于 String 这个对象的。除此之外还有一个 hash 成员变量,是该 String 对象的哈希值的缓存,这个成员变量也和本文的讨论无关。在Java中,数组也是对象。 所以 value 也只是一个引用,它指向一个真正的数组对象。其实执行了String s = “ABCabc”; 这句代码之后,真正的内存布局应该是这样的:

  字符串在 Java 中是不可变的,因为 String 对象缓存在字符串常量池中。由于缓存的字符串在多个客户之间共享,因此始终存在风险,其中一个客户的操作会影响所有其他客户。例如,如果一段代码将 String “Test” 的值更改为 “TEST”,则所有其他客户也将看到该值。由于 String 对象的缓存性能是很重要的一方面,因此通过使 String 类不可变来避免这种风险。

  同时,String 是 final 的,因此没有人可以通过扩展和覆盖行为来破坏 String 类的不变性、缓存、散列值的计算等

  String 类不可变的另一个原因可能是由于 HashMap,由于把字符串作为 HashMap 键很受欢迎。对于键值来说,重要的是它们是不可变的,以便用它们检索存储在 HashMap 中的值对象。

  由于 HashMap 的工作原理是散列,因此需要具有相同的值才能正常运行。如果在插入后修改了 String 的内容,可变的 String将在插入和检索时生成两个不同的哈希码,可能会丢失 Map 中的值对象。

  String 作为数据类型,传输对象和中间人角色的重要性和流行性也使这个问题在 Java 面试中很常见。

  为什么 String 在 Java 中是不可变的是 Java 中最常被问到的字符串访问问题之一,它首先讨论了什么是 String,Java 中的 String 如何与 C 和 C++ 中的 String 不同,然后转向在Java中什么是不可变对象,不可变对象有什么好处,为什么要使用它们以及应该使用哪些场景。

  这个问题有时也会问:“为什么 String 在 Java 中是 final 的”。我认为以下几点解释了为什么 String 类在 Java 中是不可变的或 final 的:

  • 1、想象字符串池没有使字符串不可变的话,是站不住脚的,因为在字符串池的情况下,一个字符串对象/文字,例如 “Test” 已被许多参考变量引用,因此如果其中任何一个更改了值,其他参数将自动受到影响,如下:
代码语言:javascript
复制
String A="Test";
String B="Test";

  现在字符串 B 调用 “Test”.toUpperCase, 将同一个对象改为“TEST”,所以 A 也是 “TEST”,这肯定是不行的。

  • 2、字符串已被广泛用作许多 Java 类的参数,例如,为了打开网络连接,你可以将主机名和端口号作为字符串传递,你可以将数据库 URL 作为字符串传递, 以打开数据库连接,你可以通过将文件名作为参数传递给 File I/O 类来打开 Java 中的任何文件。如果 String 不是不可变的,这将导致严重的安全威胁,我的意思是有人可以访问他有权授权的任何文件,然后可以故意或意外地更改文件名并获得对该文件的访问权限。由于不变性,你无需担心这种威胁。这个原因也说明了,为什么 String 在 Java 中是最终的,通过使 java.lang.String final,Java设计者确保没有人覆盖 String 类的任何行为。
  • 3、由于 String 是不可变的,它可以安全地共享许多线程,这对于多线程编程非常重要,并且避免了 Java 中的同步问题,不变性也使得String 实例在 Java 中是线程安全的,这意味着你不需要从外部同步 String 操作。关于 String 的另一个要点是由截取字符串 SubString 引起的内存泄漏,这不是与线程相关的问题,但也是需要注意的。
  • 4、为什么 String 在 Java 中是不可变的另一个原因是允许 String 缓存其哈希码,Java 中的不可变 String 缓存其哈希码,并且不会在每次调用 String 的 hashcode 方法时重新计算,这使得它在 Java 中的 HashMap 中使用的 HashMap 键非常快。简而言之,因为 String 是不可变的,所以没有人可以在创建后更改其内容,这保证了 String 的 hashCode 在多次调用时是相同的
  • 5、String 不可变的绝对最重要的原因是它被类加载机制使用,因此具有深刻和基本的安全考虑。如果 String 是可变的,加载“java.io.Writer” 的请求可能已被更改为加载 “mil.vogoon.DiskErasingWriter”. 安全性和字符串池是使字符串不可变的主要原因。

面试题3:为什么说 char[] 比 Java 中的 String 更适合存储密码?

  这个问题也可以定义为封装Char[]的String类相比Char数组,对密码存储会有哪些不同?,这是最近在 Java 面试中向我的一位朋友询问的问题。任何与 String 相关的问题都必须对字符串的特殊属性有一些线索,比如不变性。在这里,我们将探讨为什么你应该使用char[]存储密码而不是String的一些原因。

1、由于字符串在 Java 中是不可变的,如果你将密码存储为纯文本,它将在内存中可用,直到垃圾收集器清除它. 并且为了可重用性,会存在 String 在字符串池中, 它很可能会保留在内存中持续很长时间,从而构成安全威胁

  由于任何有权访问内存转储的人都可以以明文形式找到密码,这是另一个原因,你应该始终使用加密密码而不是纯文本。由于字符串是不可变的,所以不能更改字符串的内容,因为任何更改都会产生新的字符串,而如果你使用char[],你就可以将所有元素设置为空白或零。因此,在字符数组中存储密码可以明显降低窃取密码的安全风险。

2、Java 本身建议使用 JPasswordField 的 getPassword 方法,该方法返回一个 char[] 和不推荐使用的getTex()方法,该方法以明文形式返回密码,由于安全原因。应遵循 Java 团队的建议, 坚持标准而不是反对它。

3、使用 String 时,总是存在在日志文件或控制台中打印纯文本的风险,但如果使用 Array,则不会打印数组的内容而是打印其内存位置。虽然不是一个真正的原因,但仍然有道理。

代码语言:javascript
复制
String strPassword =“Unknown”; char [] charPassword = new char [] {'U','n','k','w','o','n'}; 
System.out.println(“字符密码:”+ strPassword);
System.out.println(“字符密码:”+ charPassword);

输出:

代码语言:javascript
复制
字符串密码:Unknown
字符密码:[C @110b053

  我还建议使用散列或加密的密码而不是纯文本,并在验证完成后立即从内存中清除它。因此,在Java中,用字符数组用存储密码比字符串是更好的选择。虽然仅使用char[]还不够,还你需要擦除内容才能更安全。

每日小结

  今天我们复习了Java基础知识中常考的两个老油条问题,你做到心中有数了么?对了,如果你的朋友也在准备面试,请将这个系列扔给他,如果他认真对待,肯定会感谢你的!!好了,今天就到这里,学废了的同学,记得在评论区留言:打卡。,给同学们以激励。

参考资料

https://v3.processon.com/view/5ef1a2917d9c0844202f7746 https://blog.csdn.net/qq_45737068/article/details/107149922 https://www.cnblogs.com/weirdo-lenovo/p/11418871.html

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-02-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 车票
  • 面试题1:String str与new String与有什么区别?
  • 面试题2:为什么 String 在 Java 中是不可变(final)的?
  • 面试题3:为什么说 char[] 比 Java 中的 String 更适合存储密码?
  • 每日小结
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档