10 个最难回答的 Java 面试题
这是我收集的 10 个最棘手的 Java 面试问题列表. 这些问题主要来自 Java 核心部分 , 不涉及 Java EE 相关问题. 你可能知道这些棘手的 Java 问题的答案, 或者觉得这些不足以挑战你的 Java 知识, 但这些问题都是容易在各种 Java 面试中被问到的, 而且包括我的朋友和同事在内的许多程序员都觉得很难回答.
1. 为什么等待和通知是在 Object 类而不是 Thread 中声明的?
一个棘手的 Java 问题, 如果 Java 编程语言不是你设计的, 你怎么能回答这个问题呢. Java 编程的常识和深入了解有助于回答这种棘手的 Java 核心方面的面试问题.
为什么 wait,notify 和 notifyAll 是在 Object 类中定义的而不是在 Thread 类中定义
这是有名的 Java 面试问题, 招 2~4 年经验的到高级 Java 开发人员面试都可能碰到.
这个问题的好在它能反映了面试者对等待通知机制的了解, 以及他对此主题的理解是否明确. 就像为什么 Java 中不支持多继承或者为什么 String 在 Java 中是 final 的问题一样, 这个问题也可能有多个答案.
为什么在 Object 类中定义 wait 和 notify 方法, 每个人都能说出一些理由. 从我的面试经验来看, wait 和 nofity 仍然是大多数 Java 程序员最困惑的, 特别是 2 到 3 年的开发人员, 如果他们要求使用 wait 和 notify, 他们会很困惑. 因此, 如果你去参加 Java 面试, 请确保对 wait 和 notify 机制有充分的了解, 并且可以轻松地使用 wait 来编写代码, 并通过生产者 - 消费者问题或实现阻塞队列等了解通知的机制.
为什么等待和通知需要从同步块或方法中调用, 以及 Java 中的 wait,sleep 和 yield 方法之间的差异, 如果你还没有读过, 你会觉得有趣. 为何 wait,notify 和 notifyAll 属于 Object 类? 为什么它们不应该在 Thread 类中? 以下是我认为有意义的一些想法:
1) wait 和 notify 不仅仅是普通方法或同步工具, 更重要的是它们是 Java 中两个线程之间的通信机制. 对语言设计者而言, 如果不能通过 Java 关键字 (例如 synchronized) 实现通信此机制, 同时又要确保这个机制对每个对象可用, 那么 Object 类则是的正确声明位置. 记住同步和等待通知是两个不同的领域, 不要把它们看成是相同的或相关的. 同步是提供互斥并确保 Java 类的线程安全, 而 wait 和 notify 是两个线程之间的通信机制.
2) 每个对象都可上锁, 这是在 Object 类而不是 Thread 类中声明 wait 和 notify 的另一个原因.
3) 在 Java 中为了进入代码的临界区, 线程需要锁定并等待锁定, 他们不知道哪些线程持有锁, 而只是知道锁被某个线程持有, 并且他们应该等待取得锁, 而不是去了解哪个线程在同步块内, 并请求它们释放锁定.
4) Java 是基于 Hoare 的监视器的思想(. 在 Java 中, 所有对象都有一个监视器.
线程在监视器上等待, 为执行等待, 我们需要 2 个参数:
一个线程
一个监视器(任何对象)
在 Java 设计中, 线程不能被指定, 它总是运行当前代码的线程. 但是, 我们可以指定监视器(这是我们称之为等待的对象). 这是一个很好的设计, 因为如果我们可以让任何其他线程在所需的监视器上等待, 这将导致 "入侵", 导致在设计并发程序时会遇到困难. 请记住, 在 Java 中, 所有在另一个线程的执行中侵入的操作都被弃用了(例如 stop 方法).
2. 为什么 Java 中不支持多重继承?
- A foo()
- / \
- / \
- foo() B C foo()
- \ /
- \ /
- D foo()
- String A="Test";
- String B="Test";
- String strPassword ="Unknown";
- char [] charPassword = new char [] {'U','n','k','w','o','n'};
- System.out.println("字符密码:"+ strPassword);
- System.out.println("字符密码:"+ charPassword);
- /**
- * 使用 Java 枚举的单例模式示例
- */
- public enum EasySingleton{
- INSTANCE;
- }
- /**
- * 单例模式示例, 双重锁定检查
- */
- public class DoubleCheckedLockingSingleton{
- private volatile DoubleCheckedLockingSingleton INSTANCE;
- private DoubleCheckedLockingSingleton(){}
- public DoubleCheckedLockingSingleton getInstance(){
- if(INSTANCE == null){
- synchronized(DoubleCheckedLockingSingleton.class){
- //double checking Singleton instance
- if(INSTANCE == null){
- INSTANCE = new DoubleCheckedLockingSingleton();
- }
- }
- }
- return INSTANCE;
- }
- }
- /**
- * 单例模式示例与静态工厂方法
- */
- public class Singleton{
- //initailzed during class loading
- private static final Singleton INSTANCE = new Singleton();
- //to prevent creating another instance of Singleton
- private Singleton(){}
- public static Singleton getSingleton(){
- return INSTANCE;
- }
- }
- //readResolve to prevent another instance of Singleton
- private Object readResolve(){
- return INSTANCE;
- }
- /**
- * Java 程序通过强制循环等待来创建死锁.
- *
- *
- */
- public class DeadLockDemo {
- /*
- * 此方法请求两个锁, 第一个字符串, 然后整数
- */
- public void method1() {
- synchronized (String.class) {
- System.out.println("Aquired lock on String.class object");
- synchronized (Integer.class) {
- System.out.println("Aquired lock on Integer.class object");
- }
- }
- }
- /*
- * 此方法也请求相同的两个锁, 但完全
- * 相反的顺序, 即首先整数, 然后字符串.
- * 如果一个线程持有字符串锁, 则这会产生潜在的死锁
- * 和其他持有整数锁, 他们等待对方, 永远.
- */
- public void method2() {
- synchronized (Integer.class) {
- System.out.println("Aquired lock on Integer.class object");
- synchronized (String.class) {
- System.out.println("Aquired lock on String.class object");
- }
- }
- }
- }
- public class DeadLockFixed {
- /**
- * 两种方法现在都以相同的顺序请求锁, 首先采用整数, 然后是 String.
- * 你也可以做反向, 例如, 第一个字符串, 然后整数,
- * 只要两种方法都请求锁定, 两者都能解决问题
- * 顺序一致.
- */
- public void method1() {
- synchronized (Integer.class) {
- System.out.println("Aquired lock on Integer.class object");
- synchronized (String.class) {
- System.out.println("Aquired lock on String.class object");
- }
- }
- }
- public void method2() {
- synchronized (Integer.class) {
- System.out.println("Aquired lock on Integer.class object");
- synchronized (String.class) {
- System.out.println("Aquired lock on String.class object");
- }
- }
- }
- }
- /**
- *
- * Java program which demonstrate that we can not override static method in Java.
- * Had Static method can be overridden, with Super class type and sub class object
- * static method from sub class would be called in our example, which is not the case.
- */
- public class CanWeOverrideStaticMethod {
- public static void main(String args[]) {
- Screen scrn = new ColorScreen();
- //if we can override static , this should call method from Child class
- scrn.show(); //IDE will show warning, static method should be called from classname
- }
- }
- class Screen{
- /*
- * public static method which can not be overridden in Java
- */
- public static void show(){
- System.out.printf("Static method from parent class");
- }
- }
- class ColorScreen extends Screen{
- /*
- * static method of same name and method signature as existed in super
- * class, this is not method overriding instead this is called
- * method hiding in Java
- */
- public static void show(){
- System.err.println("Overridden static method in Child Class in Java");
- }
- }
来源: https://segmentfault.com/a/1190000019962661