Java进阶面试题(网上资料整理)

参考:10 个最难回答的 Java 问题

文章目录

  • 1.为什么notify和wait是在 Object 类而不是 Thread 中声明的
  • 2.为什么Java中不支持多重继承
  • 3.为什么Java不支持运算符重载
  • 4.为什么 String 在 Java 中是不可变的
  • 5.为什么char[]比String更适合存储敏感信息
  • 6.

1.为什么notify和wait是在 Object 类而不是 Thread 中声明的

  • wait 和 notify 不仅仅是普通方法或同步工具,更重要的是它们是 Java 中两个线程之间的通信机制。
    对语言设计者而言, 如果不能通过 Java 关键字(例如 synchronized)实现通信此机制,同时又要确保这个机制对每个对象可用, 那么 Object 类则是的正确声明位置。记住同步和等待通知是两个不同的领域,不要把它们看成是相同的或相关的。同步是提供互斥并确保 Java 类的线程安全,而 wait 和 notify 是两个线程之间的通信机制。
  • 每个对象都可上锁,所以在 Object 类而不是 Thread 类中声明 wait 和 notify。
  • 在 Java 中为了进入代码的临界区,线程需要锁定并等待锁定,他们不知道哪些线程持有锁,而只是知道锁被某个线程持有, 并且他们应该等待取得锁, 而不是去了解哪个线程在同步块内,并请求它们释放锁定。
  • Java 是基于 Hoare 的监视器的思想。在Java中,所有对象都有一个监视器。
    线程在监视器上等待,为执行等待,我们需要2个参数:一个线程,一个监视器(任何对象)
    在 Java 设计中,线程不能被指定,它总是运行当前代码的线程。但是,我们可以指定监视器(这是我们称之为等待的对象)。这是一个很好的设计,因为如果我们可以让任何其他线程在所需的监视器上等待,这将导致“入侵”,导致在设计并发程序时会遇到困难。请记住,在 Java 中,所有在另一个线程的执行中侵入的操作都被弃用了(例如 stop 方法)。

2.为什么Java中不支持多重继承

  • 钻石形继承问题产生的歧义
    考虑一个类 A 有 foo() 方法, 然后 B 和 C 派生自 A, 并且有自己的 foo() 实现,现在 D 类使用多个继承派生自 B 和C,如果我们只引用 foo(), 编译器将无法决定它应该调用哪个 foo()。

  • 多重继承确实使设计复杂化并在转换、构造函数链接等过程中产生问题。
    假设你需要多重继承的情况并不多,简单起见,明智的决定是省略它。此外,Java 可以通过使用接口支持单继承来避免这种歧义。由于接口只有方法声明而且没有提供任何实现,因此只有一个特定方法的实现,因此不会有任何歧义。

3.为什么Java不支持运算符重载

  • 简单性和清晰性
    清晰性是Java设计者的目标之一。设计者不是只想复制语言,而是希望拥有一种清晰,真正面向对象的语言。添加运算符重载比没有它肯定会使设计更复杂,并且它可能导致更复杂的编译器, 或减慢 JVM,因为它需要做额外的工作来识别运算符的实际含义,并减少优化的机会, 以保证 Java 中运算符的行为。
  • 避免编程错误
    Java 不允许用户定义的运算符重载,因为如果允许程序员进行运算符重载,将为同一运算符赋予多种含义,这将使任何开发人员的学习曲线变得陡峭,事情变得更加混乱。据观察,当语言支持运算符重载时,编程错误会增加,从而增加了开发和交付时间。由于 Java 和 JVM 已经承担了大多数开发人员的责任,如在通过提供垃圾收集器进行内存管理时,因为这个功能增加污染代码的机会, 成为编程错误之源, 因此没有多大意义。
  • JVM复杂性
    从JVM的角度来看,支持运算符重载使问题变得更加困难。通过更直观,更干净的方式使用方法重载也能实现同样的事情,因此不支持 Java 中的运算符重载是有意义的。与相对简单的 JVM 相比,复杂的 JVM 可能导致 JVM 更慢,并为保证在 Java 中运算符行为的确定性从而减少了优化代码的机会。
  • 让开发工具处理更容易
    这是在 Java 中不支持运算符重载的另一个好处。省略运算符重载使语言更容易处理,这反过来又更容易开发处理语言的工具,例如 IDE 或重构工具。Java 中的重构工具远胜于 C++。

4.为什么 String 在 Java 中是不可变的

  • 可以安全地共享许多线程
    这对于多线程编程非常重要. 并且避免了 Java 中的同步问题,不变性也使得String 实例在 Java 中是线程安全的,这意味着你不需要从外部同步 String 操作。
  • 允许 String 缓存其哈希码
    Java 中的不可变 String 缓存其哈希码,并且不会在每次调用 String 的 hashcode 方法时重新计算,这使得它在 Java 中的 HashMap 中使用的 HashMap 键非常快。简而言之,因为 String 是不可变的,所以没有人可以在创建后更改其内容,这保证了 String 的 hashCode 在多次调用时是相同的。
  • 它被类加载机制使用,因此具有深刻和基本的安全考虑。
    如果 String 是可变的,加载“java.io.Writer” 的请求可能已被更改为加载 “mil.vogoon.DiskErasingWriter”. 安全性和字符串池是使字符串不可变的主要原因。

5.为什么char[]比String更适合存储敏感信息

  • 字符串在Java中是不可变的,char[]可以被设置为其他值
    由于字符串是不可变的,所以不能更改字符串的内容,因为任何更改都会产生新的字符串,它将在内存中可用,直到垃圾收集器清除它。并且为了可重用性,会存储在字符串池中,它很可能会保留在内存中持续很长时间,从而构成安全威胁。
    而如果你使用char[],你就可以将所有元素设置为空白或零。因此,在字符数组中存储密码可以明显降低窃取密码的安全风险。
  • 打印的问题
    使用String时,总是存在在日志文件或控制台中打印纯文本的风险,但如果使用Array,则不会打印数组的内容而是打印其内存位置。

6.

你可能感兴趣的:(面试)