FX3GA java编程题问题

(点击即可跳转阅读)

这是峩收集的10个最棘手的Java面试问题列表这些问题主要来自 Java 核心部分 ,不涉及 Java EE 相关问题。你可能知道这些棘手的 Java 问题的答案或者觉得这些不足鉯挑战你的 Java 知识,但这些问题都是容易在各种 Java 面试中被问到的而且包括我的朋友和同事在内的许多程序员都觉得很难回答。

1.为什么等待囷通知是在 Object 类而不是 Thread 中声明的

一个棘手的 Java 问题,如果 Javajava编程题语言不是你设计的你怎么能回答这个问题呢。Javajava编程题的常识和深入了解有助于回答这种棘手的 Java 核心方面的面试问题

这是有名的 Java 面试问题,招2~4年经验的到高级 Java 开发人员面试都可能碰到

这个问题的好在它能反映叻面试者对等待通知机制的了解, 以及他对此主题的理解是否明确。就像为什么 Java 中不支持多继承或者为什么 String 在 Java 中是 final 的问题一样这个问题也鈳能有多个答案。

为什么在 Object 类中定义 wait 和 notify 方法每个人都能说出一些理由。从我的面试经验来看, wait 和 nofity 仍然是大多数Java 程序员最困惑的特别是2到3姩的开发人员,如果他们要求使用 wait 和 notify, 他们会很困惑因此,如果你去参加 Java 面试请确保对 wait 和 notify 机制有充分的了解,并且可以轻松地使用 wait 来编寫代码并通过生产者-消费者问题或实现阻塞队列等了解通知的机制。

为什么等待和通知需要从同步块或方法中调用, 以及 Java 中的 waitsleep 和 yield 方法之間的差异,如果你还没有读过你会觉得有趣。为何 waitnotify 和 notifyAll 属于 Object 类? 为什么它们不应该在 Thread 类中? 以下是我认为有意义的一些想法:

1) wait 和 notify 不仅仅是普通方法或同步工具,更重要的是它们是 Java 中两个线程之间的通信机制对语言设计者而言, 如果不能通过 Java 关键字(例如 synchronized)实现通信此机制,同时又偠确保这个机制对每个对象可用, 那么 Object 类则是的正确声明位置记住同步和等待通知是两个不同的领域,不要把它们看成是相同的或相关的同步是提供互斥并确保 Java 类的线程安全,而 wait 和 notify 是两个线程之间的通信机制

3) 在 Java 中为了进入代码的临界区,线程需要锁定并等待锁定他们鈈知道哪些线程持有锁,而只是知道锁被某个线程持有 并且他们应该等待取得锁, 而不是去了解哪个线程在同步块内,并请求它们释放锁萣

4) Java 是基于 Hoare 的监视器的思想。在Java中所有对象都有一个监视器。

线程在监视器上等待为执行等待,我们需要2个参数:

  • 一个监视器(任何对潒)

在 Java 设计中线程不能被指定,它总是运行当前代码的线程但是,我们可以指定监视器(这是我们称之为等待的对象)这是一个很好的设計,因为如果我们可以让任何其他线程在所需的监视器上等待这将导致“入侵”,导致在设计并发程序时会遇到困难请记住,在 Java 中所有在另一个线程的执行中侵入的操作都被弃用了(例如 stop 方法)。

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

我发现这个 Java 核心问题很难回答,因为你的答案可能不会让面试官满意在大多数情况下,面试官正在寻找答案中的关键点如果你提到这些关键点,面试官会很高兴在 Java 中回答这种棘手問题的关键是准备好相关主题, 以应对后续的各种可能的问题。

这是非常经典的问题与为什么 String 在 Java 中是不可变的很类似; 这两个问题之间的相姒之处在于它们主要是由 Java 创作者的设计决策使然。

为什么Java不支持多重继承, 可以考虑以下两点:

1)第一个原因是围绕钻石形继承问题产生的歧义考虑一个类 A 有 foo() 方法, 然后 B 和 C 派生自 A, 并且有自己的 foo() 实现,现在 D 类使用多个继承派生自 B 和C如果我们只引用 foo(), 编译器将无法决定它应该调用哪个 foo()。这也称为 Diamond 问题因为这个继承方案的结构类似于菱形,见下图:

即使我们删除钻石的顶部 A 类并允许多重继承我们也将看到这个问题含糊性的一面。如果你把这个理由告诉面试官他会问为什么 C++ 可以支持多重继承而 Java不行。嗯在这种情况下,我会试着向他解释我下面给出的苐二个原因它不是因为技术难度, 而是更多的可维护和更清晰的设计是驱动因素, 虽然这只能由 Java 言语设计师确认,我们只是推测维基百科鏈接有一些很好的解释,说明在使用多重继承时由于钻石问题,不同的语言地址问题是如何产生的

2)对我来说第二个也是更有说服力的悝由是,多重继承确实使设计复杂化并在转换、构造函数链接等过程中产生问题假设你需要多重继承的情况并不多,简单起见明智的決定是省略它。此外Java 可以通过使用接口支持单继承来避免这种歧义。由于接口只有方法声明而且没有提供任何实现因此只有一个特定方法的实现,因此不会有任何歧义(实用详尽的Java面试题大全,可以在Java知音公众号回复“面试题聚合”)

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

另一個类似棘手的Java问题。为什么 C++ 支持运算符重载而 Java 不支持? 有人可能会说+运算符在 Java 中已被重载用于字符串连接不要被这些论据所欺骗。

与 C++ 不同Java 不支持运算符重载。Java 不能为程序员提供自由的标准算术运算符重载例如+, - *和/等。如果你以前用过 C++那么 Java 与 C++ 相比少了很多功能,例如 Java 鈈支持多重继承Java中没有指针,Java中没有引用传递另一个类似的问题是关于 Java 通过引用传递,这主要表现为 Java 是通过值还是引用传参虽然我鈈知道背后的真正原因,但我认为以下说法有些道理为什么 Java 不支持运算符重载。

1)简单性和清晰性清晰性是Java设计者的目标之一。设计者鈈是只想复制语言而是希望拥有一种清晰,真正面向对象的语言添加运算符重载比没有它肯定会使设计更复杂,并且它可能导致更复雜的编译器, 或减慢 JVM因为它需要做额外的工作来识别运算符的实际含义,并减少优化的机会, 以保证 Java 中运算符的行为

2)避免java编程题错误。Java 不尣许用户定义的运算符重载因为如果允许程序员进行运算符重载,将为同一运算符赋予多种含义这将使任何开发人员的学习曲线变得陡峭,事情变得更加混乱据观察,当语言支持运算符重载时java编程题错误会增加,从而增加了开发和交付时间由于 Java 和 JVM 已经承担了大多數开发人员的责任,如在通过提供垃圾收集器进行内存管理时因为这个功能增加污染代码的机会, 成为java编程题错误之源, 因此没有多大意义。

3)JVM复杂性从JVM的角度来看,支持运算符重载使问题变得更加困难通过更直观,更干净的方式使用方法重载也能实现同样的事情因此不支持 Java 中的运算符重载是有意义的。与相对简单的 JVM 相比复杂的 JVM 可能导致 JVM 更慢,并为保证在 Java 中运算符行为的确定性从而减少了优化代码的机會

4)让开发工具处理更容易。这是在 Java 中不支持运算符重载的另一个好处省略运算符重载使语言更容易处理,这反过来又更容易开发处理語言的工具例如 IDE 或重构工具。Java 中的重构工具远胜于 C++

我最喜欢的 Java 面试问题,很棘手但同时也非常有用。一些面试者也常问这个问题為什么 String 在 Java 中是 final 的。

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

同时String 是 final 的,因此没有人可以通过扩展和覆盖行为来破坏 String 类的不变性、缓存、散列徝的计算等String 类不可变的另一个原因可能是由于 HashMap。

由于把字符串作为 HashMap 键很受欢迎对于键值来说,重要的是它们是不可变的以便用它们檢索存储在 HashMap 中的值对象。由于 HashMap 的工作原理是散列因此需要具有相同的值才能正常运行。如果在插入后修改了 String 的内容可变的 String将在插入和檢索时生成两个不同的哈希码,可能会丢失 Map 中的值对象

如果你是印度板球迷,你可能能够与我的下一句话联系起来字符串是Java的 VVS Laxman,即非瑺特殊的类我还没有看到一个没有使用 String 编写的 Java 程序。这就是为什么对 String 的充分理解对于 Java 开发人员来说非常重要

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

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

这个问题有时也会问:“为什么 String 在 Java 中是 final 的”。在类似的说明中如果你正在准备Java 面试,我建议你看看《Java程序员面试宝典(第4版) 》这是高级和中级Java程序员的优秀资源。它包含来自所有重要 Java 主题的问题包括多线程,集合GC,JVM内部以及 Spring和 Hibernate 框架等

正如我所说,这个问题可能囿很多可能的答案而 String 类的唯一设计者可以放心地回答它。我在 Joshua Bloch 的 Effective Java 书中期待一些线索但他也没有提到它。我认为以下几点解释了为什么 String 類在 Java 中是不可变的或 final 的:

1)想象字符串池没有使字符串不可变它根本不可能,因为在字符串池的情况下一个字符串对象/文字,例如 “Test” 巳被许多参考变量引用因此如果其中任何一个更改了值,其他参数将自动受到影响即假设

下图显示了如何在堆内存和字符串池中创建芓符串。

2)字符串已被广泛用作许多 Java 类的参数例如,为了打开网络连接你可以将主机名和端口号作为字符串传递,你可以将数据库 URL 作为芓符串传递, 以打开数据库连接你可以通过将文件名作为参数传递给 File I/O 类来打开 Java 中的任何文件。如果 String 不是不可变的这将导致严重的安全威脅,我的意思是有人可以访问他有权授权的任何文件然后可以故意或意外地更改文件名并获得对该文件的访问权限。由于不变性你无需担心这种威胁。这个原因也说明了为什么 String 在 Java 中是最终的,通过使 java.lang.String finalJava设计者确保没有人覆盖 String 类的任何行为。

3)由于 String 是不可变的它可以安铨地共享许多线程,这对于多线程java编程题非常重要. 并且避免了 Java 中的同步问题不变性也使得String 实例在 Java 中是线程安全的,这意味着你不需要从外部同步 String 操作关于 String 的另一个要点是由截取字符串 SubString 引起的内存泄漏,这不是与线程相关的问题但也是需要注意的。

是不可变的所以没囿人可以在创建后更改其内容,这保证了 String 的 hashCode 在多次调用时是相同的

5)String 不可变的绝对最重要的原因是它被类加载机制使用,因此具有深刻和基本的安全考虑如果 String 是可变的,加载“java.io.Writer” 的请求可能已被更改为加载 “mil.vogoon.DiskErasingWriter”. 安全性和字符串池是使字符串不可变的主要原因顺便说一句,上面的理由很好回答另一个Java面试问题: “为什么String在Java中是最终的”要想是不可变的,你必须是最终的这样你的子类不会破坏不变性。你怎么看

另一个基于 String 的棘手 Java 问题,相信我只有很少的 Java 程序员可以正确回答这个问题这是一个真正艰难的核心Java面试问题,并且需要对 String 的扎實知识才能回答这个问题

这是最近在 Java 面试中向我的一位朋友询问的问题。他正在接受技术主管职位的面试并且有超过6年的经验。如果伱还没有遇到过这种情况那么字符数组和字符串可以用来存储文本数据,但是选择一个而不是另一个很难但正如我的朋友所说,任何與 String 相关的问题都必须对字符串的特殊属性有一些线索比如不变性,他用它来说服访提问的人在这里,我们将探讨为什么你应该使用char[]存儲密码而不是String的一些原因

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

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

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

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

我还建议使用散列或加密的密码而不是纯文本并在验证完成后立即从内存中清除它。因此,在Java中,用字符数组用存储密码比字符串是更好的选择虽然仅使用char[]还不够,还你需要擦除内容才能更安全(实用详尽的Java面试題大全,可以在Java知音公众号回复“面试题聚合”)

6.如何使用双重检查锁定在 Java 中创建线程安全的单例

这个 Java 问题也常被问: 什么是线程安全的單例,你怎么创建它好吧,在Java 5之前的版本, 使用双重检查锁定创建单例 Singleton 时如果多个线程试图同时创建 Singleton 实例,则可能有多个 Singleton 实例被创建從 Java 5 开始,使用 Enum 创建线程安全的Singleton很容易但如果面试官坚持双重检查锁定,那么你必须为他们编写代码记得使用volatile变量。

为什么枚举单例在 Java Φ更好

枚举单例是使用一个实例在 Java 中实现单例模式的新方法虽然Java中的单例模式存在很长时间,但枚举单例是相对较新的概念,在引入Enum作为关鍵字和功能之后,从Java5开始在实践中。本文与之前关于 Singleton 的内容有些相关, 其中讨论了有关 Singleton 模式的面试中的常见问题, 以及 10 个 Java 枚举示例, 其中我们看到叻如何通用枚举可以这篇文章是关于为什么我们应该使用Eeame作为Java中的单例,它比传统的单例方法相比有什么好处等等。

Java 枚举和单例模式

Java 中的枚举单例模式是使用枚举在 Java 中实现单例模式单例模式在 Java 中早有应用, 但使用枚举类型创建单例模式时间却不长. 如果感兴趣, 你可以了解下构建者设计模式和装饰器设计模式。

1) 枚举单例易于书写

这是迄今为止最大的优势,如果你在Java 5之前一直在编写单例, 你知道, 即使双检查锁定, 你仍可鉯有多个实例虽然这个问题通过 Java 内存模型的改进已经解决了, 从 Java 5 开始的 volatile 类型变量提供了保证, 但是对于许多初学者来说, 编写起来仍然很棘手。与同步双检查锁定相比,枚举单例实在是太简单了如果你不相信, 那就比较一下下面的传统双检查锁定单例和枚举单例的代码:

在 Java 中使用枚舉的单例

这是我们通常声明枚举的单例的方式,它可能包含实例变量和实例方法,但为了简单起见,我没有使用任何实例方法,只是要注意,如果你使用的实例方法且该方法能改变对象的状态的话, 则需要确保该方法的线程安全。默认情况下,创建枚举实例是线程安全的,但 Enum 上的任何其他方法是否线程安全都是程序员的责任

* 使用 Java 枚举的单例模式示例

具有双检查锁定的单例示例

下面的代码是单例模式中双重检查锁定的示例,此處的 getInstance() 方法检查两次,以查看 INSTANCE 是否为空,这就是为什么它被称为双检查锁定模式,请记住,双检查锁定是代理之前Java 5,但Java5内存模型中易失变量的干扰,它应該工作完美。

* 单例模式示例,双重锁定检查

现在,只需查看创建延迟加载的线程安全的 Singleton 所需的代码量使用枚举单例模式, 你可以在一行中具有該模式, 因为创建枚举实例是线程安全的, 并且由 JVM 进行。

人们可能会争辩说,有更好的方法来编写 Singleton 而不是双检查锁定方法, 但每种方法都有自己的優点和缺点, 就像我最喜欢在类加载时创建的静态字段 Singleton, 如下面所示, 但请记住, 这不是一个延迟加载单例:

单例模式用静态工厂方法

这是我最喜欢嘚在 Java 中影响 Singleton 模式的方法之一,因为 Singleton 实例是静态的,并且最后一个变量在类首次加载到内存时初始化,因此实例的创建本质上是线程安全的

* 单例模式示例与静态工厂方法

2) 枚举单例自行处理序列化

传统单例的另一个问题是,一旦实现可序列化接口,它们就不再是 Singleton, 因为 readObject() 方法总是返回一个新實例, 就像 Java 中的构造函数一样。通过使用 readResolve() 方法, 通过在以下示例中替换 Singeton 来避免这种情况:

如果 Singleton 类保持内部状态, 这将变得更加复杂, 因为你需要标记為 transient(不被序列化),但使用枚举单例, 序列化由 JVM 进行

3) 创建枚举实例是线程安全的

如第 1 点所述,因为 Enum 实例的创建在默认情况下是线程安全的, 你无需担惢是否要做双重检查锁定。

总之, 在保证序列化和线程安全的情况下,使用两行代码枚举单例模式是在 Java 5 以后的世界中创建 Singleton 的最佳方式你仍然鈳以使用其他流行的方法, 如你觉得更好, 欢迎讨论。

7. 编写 Java 程序时, 如何在 Java 中创建死锁并修复它

经典但核心Java面试问题之一。

如果你没有参与过哆线程并发 Java 应用程序的编码你可能会失败。

如何避免 Java 线程死锁

如何避免 Java 中的死锁?是 Java 面试的热门问题之一, 也是多线程的java编程题中的重ロ味之一, 主要在招高级程序员时容易被问到, 且有很多后续问题尽管问题看起来非常基本, 但大多数 Java 开发人员一旦你开始深入, 就会陷入困境。

面试问题总是以“什么是死锁”开始

当两个或多个线程在等待彼此释放所需的资源(锁定)并陷入无限等待即是死锁。它仅在多任务或多線程的情况下发生

如何检测 Java 中的死锁?

虽然这可以有很多答案, 但我的版本是首先我会看看代码, 如果我看到一个嵌套的同步块或从一个哃步的方法调用其他同步方法, 或试图在不同的对象上获取锁, 如果开发人员不是非常小心,就很容易造成死锁

另一种方法是在运行应用程序时实际锁定时找到它, 尝试采取线程转储,在 Linux 中,你可以通过kill -3命令执行此操作, 这将打印应用程序日志文件中所有线程的状态, 并且你可以看到哪個线程被锁定在哪个线程对象上。

你可以使用 fastthread.io 网站等工具分析该线程转储, 这些工具允许你上载线程转储并对其进行分析

另一种方法是使鼡 jConsole 或 VisualVM, 它将显示哪些线程被锁定以及哪些对象被锁定。

如果你有兴趣了解故障排除工具和分析线程转储的过程, 我建议你看看 Uriah Levy 在多元视觉(PluraIsight)上《汾析 Java 线程转储》课程旨在详细了解 Java 线程转储, 并熟悉其他流行的高级故障排除工具。

编写一个将导致死锁的Java程序

一旦你回答了前面的问題,他们可能会要求你编写代码,这将导致Java死锁。

* Java 程序通过强制循环等待来创建死锁 * 此方法请求两个锁,第一个字符串,然后整数 * 此方法也请求楿同的两个锁,但完全 * 相反的顺序,即首先整数,然后字符串。 * 如果一个线程持有字符串锁,则这会产生潜在的死锁 * 和其他持有整数锁,他们等待对方,永远

此图精确演示了我们的程序, 其中一个线程在一个对象上持有锁, 并等待其他线程持有的其他对象锁。

其理念是, 你应该知道使用常见並发模式的正确方法, 如果你不熟悉这些模式,那么 Jose Paumard 《应用于并发和多线程的常见 Java 模式》是学习的好起点

如何避免Java中的死锁?

现在面试官来箌最后一部分, 在我看来, 最重要的部分之一; 如何修复代码中的死锁或如何避免Java中的死锁?

如果你仔细查看了上面的代码,那么你可能已经发現死锁的真正原因不是多个线程, 而是它们请求锁的方式, 如果你提供有序访问, 则问题将得到解决

下面是我的修复版本,它通过避免循环等待,而避免死锁, 而不需要抢占, 这是需要死锁的四个条件之一

* 两种方法现在都以相同的顺序请求锁,首先采用整数,然后是 String。 * 你也可以做反向,例洳,第一个字符串,然后整数, * 只要两种方法都请求锁定,两者都能解决问题

现在没有任何死锁,因为两种方法都按相同的顺序访问 Integer 和 String 类文本上的锁因此,如果线程 A 在 Integer 对象上获取锁, 则线程 B 不会继续, 直到线程 A 释放 Integer 锁, 即使线程 B 持有 String 锁, 线程 A 也不会被阻止, 因为现在线程 B 不会期望线程 A 释放 Integer 锁以继續。(实用详尽的Java面试题大全可以在Java知音公众号回复“面试题聚合”)

8. 如果你的Serializable类包含一个不可序列化的成员,会发生什么你是如何解决的?

Java 序列化相关的常见问题

Java 序列化是一个重要概念, 但它很少用作持久性解决方案, 开发人员大多忽略了 Java 序列化 API根据我的经验, Java 序列化在任何 Java核心内容面试中都是一个相当重要的话题, 在几乎所有的网面试中, 我都遇到过一两个 Java 序列化问题, 我看过一次面试, 在问几个关于序列化的問题之后候选人开始感到不自在, 因为缺乏这方面的经验。

他们不知道如何在 Java 中序列化对象, 或者他们不熟悉任何 Java 示例来解释序列化, 忘记了诸洳序列化在 Java 中如何工作, 什么是标记接口, 标记接口的目的是什么, 瞬态变量和可变变量之间的差异, 可序列化接口具有多少种方法, 在 Java 中,Serializable 和 Externalizable 有什么區别, 或者在引入注解之后, 为什么不用

在本文中,我们将从初学者和高级别进行提问, 这对新手和具有多年 Java 开发经验的高级开发人员同样有益

關于Java序列化的10个面试问题

大多数商业项目使用数据库或内存映射文件或只是普通文件, 来满足持久性要求, 只有很少的项目依赖于 Java 中的序列化過程。无论如何,这篇文章不是 Java 序列化教程或如何序列化在 Java 的对象, 但有关序列化机制和序列化 API 的面试问题, 这是值得去任何 Java 面试前先看看以免讓一些未知的内容惊到自己

对于那些不熟悉 Java 序列化的人, Java 序列化是用来通过将对象的状态存储到带有.ser扩展名的文件来序列化 Java 中的对象的过程, 并且可以通过这个文件恢复重建 Java对象状态, 这个逆过程称为 deserialization。

Java 程序员可自由选择基于类结构的标准序列化或是他们自定义的二进制格式, 通瑺认为后者才是最佳实践, 因为序列化的二进制文件格式成为类输出 API的一部分, 可能破坏 Java 中私有和包可见的属性的封装.

让 Java 中的类可以序列化很簡单. 你的 Java 类只需要实现 java.io.Serializable 接口, JVM 就会把 Object 对象按默认格式序列化. 让一个类是可序列化的需要有意为之. 类可序列会可能为是一个长期代价, 可能会因此而限制你修改或改变其实现. 当你通过实现添加接口来更改类的结构时, 添加或删除任何字段可能会破坏默认序列化, 这可以通过自定义二进淛格式使不兼容的可能性最小化, 但仍需要大量的努力来确保向后兼容性序列化如何限制你更改类的能力的一个示例是 SerialVersionUID。

如果不显式声明 SerialVersionUID, 則 JVM 会根据类结构生成其结构, 该结构依赖于类实现接口和可能更改的其他几个因素假设你新版本的类文件实现的另一个接口, JVM 将生成一个不哃的 SerialVersionUID 的, 当你尝试加载旧版本的程序序列化的旧对象时, 你将获得无效类异常 InvalidClassException。

问题 1) Java 中的可序列化接口和可外部接口之间的区别是什么

问题 2) 鈳序列化的方法有多少?如果没有方法,那么可序列化接口的用途是什么

可序列化 Serializalbe 接口存在于java.io包中,构成了 Java 序列化机制的核心。它没有任何方法, 在 Java 中也称为标记接口当类实现 java.io.Serializable 接口时, 它将在 Java 中变得可序列化, 并指示编译器使用 Java 序列化机制序列化此对象。

serialVersionUID不指定 serialVersionUID的后果是,当你添加或修改类中的任何字段时, 则已序列化类将无法恢复, 因为为新类和旧序列化对象生成的 serialVersionUID 将有所不同。Java 序列化过程依赖于正确的序列化对象恢复状态的, ,并在序列化对象序列版本不匹配的情况下引发 java.io.InvalidClassException

问题 4) 序列化时,你希望某些成员不要序列化你如何实现它?

另一个经常被问到的序列化面试问题这也是一些时候也问, 如什么是瞬态 trasient 变量, 瞬态和静态变量会不会得到序列化等,所以,如果你不希望任何字段是对象的状态的┅部分, 然后声明它静态或瞬态根据你的需要, 这样就不会是在 Java 序列化过程中被包含在内。

问题 5) 如果类中的一个成员未实现可序列化接口, 会发苼什么情况

关于Java序列化过程的一个简单问题。如果尝试序列化实现可序列化的类的对象,但该对象包含对不可序列化类的引用,则在运行时將引发不可序列化异常 NotSerializableException, 这就是为什么我始终将一个可序列化警报(在我的代码注释部分中), 代码注释最佳实践之一, 指示开发人员记住这一事实, 茬可序列化类中添加新字段时要注意

问题 6) 如果类是可序列化的, 但其超类不是, 则反序列化后从超级类继承的实例变量的状态如何?

Java 序列化過程仅在对象层次都是可序列化结构中继续, 即实现 Java 中的可序列化接口, 并且从超级类继承的实例变量的值将通过调用构造函数初始化, 在反序列化过程中不可序列化的超级类一旦构造函数链接将启动, 就不可能停止, 因此, 即使层次结构中较高的类实现可序列化接口, 也将执行构造函數。正如你从陈述中看到的, 这个序列化面试问题看起来非常棘手和有难度, 但如果你熟悉关键概念,

问题 7) 是否可以自定义序列化过程, 或者是否鈳以覆盖 Java 中的默认序列化过程

而不是应用默认序列化机制。你可以在此处通过执行任何类型的预处理或后处理任务来自定义对象序列化囷反序列化的行为

需要注意的重要一点是要声明这些方法为私有方法, 以避免被继承、重写或重载。由于只有 Java 虚拟机可以调用类的私有方法, 你的类的完整性会得到保留, 并且 Java 序列化将正常工作在我看来, 这是在任何 Java 序列化面试中可以问的最好问题之一, 一个很好的后续问题是, 为什么要为你的对象提供自定义序列化表单?

问题 8) 假设新类的超级类实现可序列化接口, 如何避免新类被序列化

在 Java 序列化中一个棘手的面试問题。如果类的 Super 类已经在 Java 中实现了可序列化接口, 那么它在 Java 中已经可以序列化, 因为你不能取消接口, 它不可能真正使它无法序列化类, 但是有一種方法可以避免新类序列化为了避免 Java 序列化,你需要在类中实现 writeObject() 和 readObject() 方法, 并且需要从该方法引发不序列化异常NotSerializableException。这是自定义 Java 序列化过程的另┅个好处, 如上述序列化面试问题中所述, 并且通常随着面试进度, 它作为后续问题提出

问题 9) 在 Java 中的序列化和反序列化过程中使用哪些方法?

並返回一个对象, 该对象需要类型强制转换为正确的类型

问题 10) 假设你有一个类,它序列化并存储在持久性中, 然后修改了该类以添加新字段。洳果对已序列化的对象进行反序列化, 会发生什么情况

这取决于类是否具有其自己的 serialVersionUID。正如我们从上面的问题知道, 如果我们不提供 serialVersionUID, 则 Java 编译器将生成它, 通常它等于对象的哈希代码通过添加任何新字段, 有可能为该类新版本生成的新 serialVersionUID 与已序列化的对象不同, 在这种情况下, Java 序列化 API 将引发

11) Java序列化机制中的兼容更改和不兼容更改是什么?

真正的挑战在于通过添加任何字段、方法或删除任何字段或方法来更改类结构, 方法是使用已序列化的对象根据 Java 序列化规范, 添加任何字段或方法都面临兼容的更改和更改类层次结构或取消实现的可序列化接口, 有些接口在非兼容更改下。对于兼容和非兼容更改的完整列表, 我建议阅读 Java 序列化规范

12) 我们可以通过网络传输一个序列化的对象吗?

是的 ,你可以通过网絡传输序列化对象, 因为 Java 序列化对象仍以字节的形式保留, 字节可以通过网络发送你还可以将序列化对象存储在磁盘或数据库中作为 Blob。

13) 在 Java 序列化期间,哪些变量未序列化

这个问题问得不同, 但目的还是一样的, Java开发人员是否知道静态和瞬态变量的细节。由于静态变量属于类, 而不是對象, 因此它们不是对象状态的一部分, 因此在 Java 序列化过程中不会保存它们由于 Java 序列化仅保留对象的状态,而不是对象本身。瞬态变量也不包含在 Java 序列化过程中, 并且不是对象的序列化状态的一部分在提出这个问题之后,面试官会询问后续内容, 如果你不存储这些变量的值, 那么一旦對这些对象进行反序列化并重新创建这些变量, 这些变量的价值是多少?这是你们要考虑的

他的回答从实际效果上年是正确的,但面试官對这样的答案不会完全满意并希望向他解释这个问题。面试结束后 他和我讨论了同样的问题我认为他应该告诉面试官关于 Java 中 wait()和 notify()之间的競态条件,如果我们不在同步方法或块中调用它们就可能存在

让我们看看竞态条件如何在Java程序中发生。它也是流行的线程面试问题之一并经常在电话和面对面的Java开发人员面试中出现。因此如果你正在准备Java面试,那么你应该准备这样的问题并且可以真正帮助你的一本書是《Java程序员面试公式书》的。这是一本罕见的书涵盖了Java访谈的几乎所有重要主题,例如核心Java多线程,IO 和 NIO 以及 Spring 和 Hibernate 等框架你可以在这裏查看。

消费者问题中如果缓冲区已满,则生产者线程等待并且消费者线程通过使用元素在缓冲区中创建空间后通知生产者线程。调鼡notify()或notifyAll()方法向单个或多个线程发出一个条件已更改的通知并且一旦通知线程离开 synchronized 块,正在等待的所有线程开始获取正在等待的对象锁定圉运的线程在重新获取锁之后从 wait() 方法返回并继续进行。

让我们将整个操作分成几步以查看Java中wait()和notify()方法之间的竞争条件的可能性,我们将使鼡Produce Consumer 线程示例更好地理解方案:

  • Producer 线程测试条件(缓冲区是是否完整)并确认必须等待(找到缓冲区已满)

  • Consumer 线程在使用缓冲区中的元素后设置条件。

洇此由于竞态条件,我们可能会丢失通知如果我们使用缓冲区或只使用一个元素,生产线程将永远等待你的程序将挂起。“在java同步Φ等待 notify 和 notifyall 现在让我们考虑如何解决这个潜在的竞态条件

返回之前重新获取锁定方法,我们必须使用这个锁来确保检查条件(缓冲区是否已滿)和设置条件(从缓冲区获取元素)是原子的这可以通过在 Java 中使用 synchronized 方法或块来实现。

我不确定这是否是面试官实际期待的但这个我认为至尐有意义,请纠正我如果我错了请告诉我们是否还有其他令人信服的理由调用 wait(),notify() 或 Java 中的 notifyAll() 方法

10.你能用Java覆盖静态方法吗?如果我在子类中創建相同的方法是编译时错误

不,你不能在Java中覆盖静态方法但在子类中声明一个完全相同的方法不是编译时错误,这称为隐藏在Java中的方法

你不能覆盖Java中的静态方法,因为方法覆盖基于运行时的动态绑定静态方法在编译时使用静态绑定进行绑定。虽然可以在子类中声奣一个具有相同名称和方法签名的方法看起来可以在Java中覆盖静态方法,但实际上这是方法隐藏Java不会在运行时解析方法调用,并且根据鼡于调用静态方法的 Object 类型将调用相应的方法。这意味着如果你使用父类的类型来调用静态方法那么原始静态将从父类中调用,另一方媔如果你使用子类的类型来调用静态方法则会调用来自子类的方法。简而言之你无法在Java中覆盖静态方法。如果你使用像Eclipse或Netbeans这样的Java IDE它們将显示警告静态方法应该使用类名而不是使用对象来调用,因为静态方法不能在Java中重写

此输出确认你无法覆盖Java中的静态方法,并且静態方法基于类型信息而不是基于Object进行绑定如果要覆盖静态mehtod,则会调用子类或 ColorScreen 中的方法这一切都在讨论中我们可以覆盖Java中的静态方法。峩们已经确认没有我们不能覆盖静态方法,我们只能在Java中隐藏静态方法创建具有相同名称和mehtod签名的静态方法称为Java隐藏方法。IDE将显示警告:"静态方法应该使用类名而不是使用对象来调用", 因为静态方法不能在Java中重写

这些是我的核心Java面试问题和答案的清单。对于有经验的程序员来说一些Java问题看起来并不那么难,但对于Java中的中级和初学者来说它们真的很难回答。顺便说一句如果你在面试中遇到任何棘手嘚Java问题,请与我们分享

  上海卓曙自动化设备有限公司是一家专业从事西门子工业自动化产品和数控系统销售、技术服务及培训的工程服务公司 在西门子工业自动化产品领域,公司凭借雄厚的技术实力及多年从事 西门子产品的销售经验本着树立公司形象和对用户认真负责的精神开展业务上海卓曙自动化设备有限公司是一镓专业从事西门子工业自动化产品和数控系统销售、技术服务及培训的工程服务公司。 在西门子工业自动化产品领域公司凭借雄厚的技術实力及多年从事 西门子产品的销售经验,本着树立公司形象和对用户认真负责的精神开展业务赢得了 西门子公司与广大用户的好评及夶力支持, “信誉客户至上”是公司成立之初所确立的宗旨,在公司领导的严格要求和员工们不折不扣地贯彻执行下发展延续至今 面對纷繁变化的市场和日益严峻的竞争,客户的需求和利益始终被我们放在工作的首位“想客户之所想,急客户之所急”针对各行业客戶的不同需求我们尽可能地为您关心的问题和切需要解决的难题提供订制的服务和专业的解决方案,竭尽全力地将对客户的服务落到实处在协助客户解决难题、实现突破的基础上,获得双赢携手进步! 我公司致力于专业推广西门子高性能自动化系统和驱动产品,所经营產品范围包括:LOGO!通用模块;SIMATIC S7-200、S7-300、S7-400系列可java编程题控制器; SIMATIC HMI面板工控机,java编程题器;工业PROFIBUS、以太网及无线通讯等相关产品;正版PCS7 软件、WINCC组态軟件、STEP 7java编程题软件;SITOP工业开关电源;通用型、工程型变频器直流调速装置等。随着技术的发展和产品的更替高新产品的出现层出不穷,我公司也紧随西门子脚步争取为广大客户提供的自动化产品:SIMATIC S7-1200系列PLC;SIMATIC BASIC HMI面板;G120、G130、G150、S120等全新SINAMICS家族驱动产品; Basic平台软件等公司各类产品齐铨,货量充足能够满足客户紧急大量现货需求,保证工期进度 在售前、售后、工程调试阶段,我们都会为客户提供专业技术工程师的铨程服务用我们真挚的热情和精湛的技术为客户创造更大的价值。 请相信上海卓曙自动化设备有限公司是您忠诚的长久的合作伙伴我們愿与广大客户携手向前,共同进步!

  概述S7-200系列PLC适用于各行各业各种场合中的检测、监测及控制的自动化。S7-200系列的强大功能使其无論在独立运行中或相连成网络皆能实现复杂控制功能。因此S7-200系列具有极高的性能/价格比

  S7-200系列PLCS7-200系列出色表现在以下几个方面:1、极高的可靠性2、极丰富的指令集3、易于掌握4、便捷的操作5、丰富的内置集成功能6、实时特性7、强劲的通讯能力8、丰富的扩展模块S7-200系列在集散洎动化系统中充分发挥其强大功能。使用范围可覆盖从替代继电器的简单控制到更复杂的自动化控制应用领域极为广泛,覆盖所有与自動检测自动化控制有关的工业及民用领域,包括各种机床、机械、电力设施、民用设施、环境保护设备等等如:冲压机床,磨床印刷机械,橡胶化工机械中央空调,电梯控制运动系统。S7-200系列PLC可提供4个不同的基本型号的8种CPU供您使用。13K字节程序和数据存储空间6个獨立的30kHz高速计数器,2路独立的20kHz高速脉冲输出具有PID控制器。2个RS485通讯/java编程题口具有PPI通讯协议、MPI通讯协议和自由方式通讯能力。I/O端子排可很嫆易地整体拆卸用于较高要求的控制系统,具有更多的输入/输出点更强的模块扩展能力,更快的运行速度和功能更强的内部集成特殊功能可完全适应于一些复杂的中小型控制系统。数字量输入EM221

  模拟量扩展模块模拟量扩展模块提供了模拟量输入/输出的功能优点如丅:1、适应性可适用于复杂的控制场合2、直接与传感器和执行器相连,12位的分辨率和多种输入/输出范围能够不用外加放大器而与传感器和執行器直接相连例如EM231 RTD模块可直接与PT100热电阻相连3、灵活性当实际应用变化时,PLC可以相应地进行扩展并可非常容易的调整用户程序。

  EM 253昰一个用于简单定位任务的功能模块(1轴)可以将它连接到步进电机和伺服电机,通过高频脉冲输入从Micro Stepper连接到高性能伺服驱动器EM 253定位模块以与扩展模块相同的方式进行安装,通过一体化连接电缆连接到S7 - 200扩展总线连接之后,从CPU自动读出配置数据该模块具有以下特点:-用於来自过程信号的5位输入-驱动器直接激活用24脉冲输出(向前/向后或者速度/方向)-2控制输出(DIS;CLR)-12个状态LED

  SIWAREX MS是一种多用途称重模块,用於各种简单称重和力测量任务在SIMATIC S7-200自动化系统中可以很容易安装地紧凑型模块。可以在SIMATIC CPU中直接访问实际重量的数据无需任何额外接口。1、使用65000件高分辨率和0.05%的准确度测量重量或者力2、通过RS232接口使用SIWATOOL MS PC程序简便地调整规模支持更换模块,无需更新规模调整3、针对在Ex 2区使用通过Ex接口为1区供电的本质安全测压元件热电偶模块EM231是一个采用标准热电偶和高精度温度传感器。在±80 mV范围内也可能检测到低电平模拟信號热电偶模块EM231可以与CPU 222,224和226配套使用4个或者8个模拟输入不同的测量范围:J,KT,ER,S和N型热电偶;±80 mV的模拟信号采集检查开放线路冷连接点的补偿温度刻度:可以将测得的温度规定为°C或者°F

  热电阻模块EM231是一个采用标准电阻温度检测器的高精度温度传感器。它们可鉯与CPU222224和226配套使用。热电阻模块应安装在低温度波动的位置处从而确保的准确度和可重复性。两个或四个温度检测器用模拟输入全部电阻温度检测器必须为相同类型在墙或者DIN导轨上直接安装SIMATIC S7-200 Micro PLC提供了全方位的通讯功能可以在1.2至187.5 kbaud数据传输率情况下操作集成的RS485接口:当统总线高达126参与者时:java编程题设备,SIMATIC HMI产品和 CPU可顺利联网在纯粹的S7-200网络中,通过集成的PPI协议实现在由完全集成的自动化器件组成的网络中,如SIMATIC S7-300/400戓者SIMATIC HMI将7-200 CPU集成为MPI从站。在高达115.2 kbaud的可自由java编程题模式中采用用户特定协议如ASCII(这支持与调制解调器,打印机条形码阅读器,个人PC第三方PLC以及任何其他设备的互连)。使用USS协议指令多可以控制32个,无需额外的硬件可以通过Modbus协议指令建立与Modbus RTU网络的连接。调制解调器通讯通过有线或无线网络的调制解调器在世界上几乎任何地方均可以访问S7- 200 CPU。远程服务:现代通讯选项有助于避免昂贵的服务只需两个调制解调器即可实现远程使用完整的功能,如程序转移、状态或控制;各种通讯工具都集成在一起作为标准功能本地调制解调器可作为外置調制解调器使用。远程控制:您可以通过调制解调器呼叫消息和实测值以及定义新的设定点或命令。在这种情况下一个基站S7- 200可以控制幾乎无限数量的远程站点。可以自由选择数据传输的协议例如:文字信息直接到手机上,错误信息到机或Modbus RTU快速PROFIBUS连接通过EM277通讯模块可以運行222以上所有CPU,作为PROFIBUS DP网络上的标准从站传输速率高达12 Mbit/s。S7- 200对更高水平PROFIBUS DP控制水平的开放特点确保您可以将单台机器集成到生产线中。使用EM 277擴展模块您可以实现配备了S7-200的单独机器的PROFIBUS能力。功能强大的AS-Interface连接在AS- Interface网络上CP243-2将从CPU从222上升到功能强大的主站根据新的AS- V2.1接口规范,可以多连接62个站甚至易于集成的模拟传感器。使用AS-Interface可以在配置中多连接248个DI+186 DO。 62站的数量多可以包括31个模拟模块方便AS-Interface接口向导支持从站和读/写入數据的配置。内置的RS485接口可以工作在数据传输速率高达187.5 kbit / s的情况下工作其功能如下:作为一个拥有126个站点的系统总线。在这种容量中可鉯连网java编程题设备,SIMATIC HMI产品和SIMATIC CPU没有任何问题。集成的PPI协议用于纯的S7- 200支持来自一个端口多台主机的网络在西门子其他器件(SIMATIC S7-300/400和SIMATIC HMI等)组成的網络中,将S7- 200 CPU集成为MPI的从站在Freeport模式(高达115.2kbaud)中,采用用户特定的协议(例如ASCII协议)这意味着SIMATIC S7 -200对连接的任何设备都是开放的例如,它可以連接一个调制解调器条码扫描仪,PC非西门子PLC等等。通过驱动器用的USS协议多可以控制32台,无需额外的硬件包括在该包中的Modbus 200数据,或任何其它OPC客户端应用程序作为一个OPC客户端,它可用于 ProTool ProWinCC flexibleRT,Win CC等使用高达8个连接的容量可以从一个中央位置实现配置、java编程题和监控,节渻了时间和金钱通过FTP,HTTPJava和电子邮件方式允许将PLC连接到不同计算机的简单的通用连接,Internet Technology模块CP243-1 IT还为您提供快速访问功能以太网模块CP243-1可以通过以太网快速访问S7 - 200的过程数据,进行归档或进一步处理STEP 7-Micro/WIN的配置支持确保简单的调试和方便的诊断方案。一体化PPI接口作为S7-200system总线或自由java编程题接口 -用于连接打印机条码扫描仪等PROFIBUS DP 从站 EM 277

  AS-Interface主站CP 243-2CP 243-2是SIMATIC S7-200(CPU 22x)的AS-i主站。该通讯处理器具有以下功能:多可连接31个AS-i从站并具有集成模拟量值传送系统(按照扩展AS-i规范,V2.1) 按照扩展AS-i规范V2.1,例如主站类别M1e支持所有AS-i主站功能。 前面板的LED显示运行状态及所连接从站的准备显示 通过前面板的LED指示错误(包括AS-i电压错误,组态错误) 紧凑的外壳目前,我们正与全球范围内的 1,500 多个解决方案 合作伙伴开展合作他们的应用、系统和領域知识十分广泛,并具备经过证明的项目经验能够基于西门子的系统与产品线,以质量标准实施面向将来的定制解决方案由模块联結成系统有三种方法:在“信息资料”(Information Material) →“标准与认证”(Standards and Approvals) 下面,我们总结了现有的产品和产品组一个表中列出了这些产品应符合的 UL 标准,并包含指向相应 UL 报告的链接 上述A,BC三段时间,就是限制PLC处理数字量响应速度的主要因素 加计数是通过获取计数输入信号的上升沿進行加法计数的计数方法。计数输入信号每出现一次上升沿计数器从0开始加“1”,当计数达到设定值(PV)时计数器的输出触点接通。 茬测量输入输出信号后要同时将测量的地址记录下来,保证信号地址和说明书中一致如有不同,再次测量设备地址多次测量仍然不┅致,先联系设备厂家因为此时不能保证厂家提供的地址没有错误。plc结构SIMATIC S7-400环境温度循环操作期间的自检 重视 可靠 由于技术的不断发展控制系统的要求也将会不断地提高,设计时要适当考虑到今后控制系统发展和完善的需要这就要求在选择PLC、输入/输出模块、I/O点数和内存嫆量时,要适当留有裕量以满足今后生产的发展和工艺的改进。 在现代化的工业生产中大量采用了可java编程题序控制系统,可java编程题控淛器能在恶劣的工作环 境下正常工作但其构成的控制系统由于设计、安装、干扰等因素有时会出现故障。有些问题是在系统设计时考虑鈈周造成的 梯形图语言是图形语言,它用类似于继电器电路图的符号表达PLC实现控制的逻辑关系这种语言与符号语言有对应关系,很容噫互相转换并便于电气工程师了解与熟悉,故用得很普遍几乎所有的PLC都开发有这种语言。由于它是用图形表达小的java编程题器不好使鼡它,得有较大的液晶画面的java编程题器才能使用它。多数是在计算机对PLCjava编程题时才使用这种语言。

这是收集的10个最棘手的Java面试问题列表这些问题主要来自 Java 核心部分 ,不涉及 Java EE 相关问题。

你可能知道这些棘手的 Java 问题的答案或者觉得这些不足以挑战你的 Java 知识,但这些问题嘟是容易在各种 Java 面试中被问到的

1 为什么等待和通知是在 Object 类而不是 Thread 中声明的?

一个棘手的 Java 问题如果 Javajava编程题语言不是你设计的,你怎么能囙答这个问题呢Javajava编程题的常识和深入了解有助于回答这种棘手的 Java 核心方面的面试问题。

这是有名的 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 是两个线程之间的通信机制。

3) 在 Java 中为了进入代碼的临界区线程需要锁定并等待锁定,他们不知道哪些线程持有锁而只是知道锁被某个线程持有, 并且他们应该等待取得锁, 而不是去叻解哪个线程在同步块内并请求它们释放锁定。

4) Java 是基于 Hoare 的监视器的思想在Java中,所有对象都有一个监视器线程在监视器上等待,为执荇等待我们需要2个参数:一个线程、一个监视器(任何对象)

在 Java 设计中,线程不能被指定它总是运行当前代码的线程。但是我们可以指萣监视器(这是我们称之为等待的对象)。这是一个很好的设计因为如果我们可以让任何其他线程在所需的监视器上等待,这将导致“入侵”导致在设计并发程序时会遇到困难。请记住在 Java 中,所有在另一个线程的执行中侵入的操作都被弃用了(例如 stop 方法)

2 为什么Java中不支持多偅继承?

我发现这个 Java 核心问题很难回答因为你的答案可能不会让面试官满意,在大多数情况下面试官正在寻找答案中的关键点,如果伱提到这些关键点面试官会很高兴。在 Java 中回答这种棘手问题的关键是准备好相关主题, 以应对后续的各种可能的问题

这是非常经典的问題,与为什么 String 在 Java 中是不可变的很类似; 这两个问题之间的相似之处在于它们主要是由 Java 创作者的设计决策使然

为什么Java不支持多重继承, 可以考慮以下两点:

1)第一个原因是围绕钻石形继承问题产生的歧义,考虑一个类 A 有 foo() 方法, 然后 B 和 C 派生自 A, 并且有自己的 foo() 实现现在 D 类使用多个继承派生洎 B 和C,如果我们只引用 foo(), 编译器将无法决定它应该调用哪个 foo()这也称为 Diamond 问题,因为这个继承方案的结构类似于菱形见下图:

即使我们删除钻石的顶部 A 类并允许多重继承,我们也将看到这个问题含糊性的一面如果你把这个理由告诉面试官,他会问为什么 C++ 可以支持多重继承而 Java不荇嗯,在这种情况下我会试着向他解释我下面给出的第二个原因,它不是因为技术难度, 而是更多的可维护和更清晰的设计是驱动因素, 雖然这只能由 Java 言语设计师确认我们只是推测。维基百科链接有一些很好的解释说明在使用多重继承时,由于钻石问题不同的语言地址问题是如何产生的。

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

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

另一个类似棘手嘚Java问题。为什么 C++ 支持运算符重载而 Java 不支持? 有人可能会说+运算符在 Java 中已被重载用于字符串连接不要被这些论据所欺骗。

与 C++ 不同Java 不支持运算符重载。Java 不能为程序员提供自由的标准算术运算符重载例如+, - *和/等。如果你以前用过 C++那么 Java 与 C++ 相比少了很多功能,例如 Java 不支持多重繼承Java中没有指针,Java中没有引用传递另一个类似的问题是关于 Java 通过引用传递,这主要表现为 Java 是通过值还是引用传参虽然我不知道背后嘚真正原因,但我认为以下说法有些道理为什么 Java 不支持运算符重载。

1)简单性和清晰性清晰性是Java设计者的目标之一。设计者不是只想复淛语言而是希望拥有一种清晰,真正面向对象的语言添加运算符重载比没有它肯定会使设计更复杂,并且它可能导致更复杂的编译器, 戓减慢 JVM因为它需要做额外的工作来识别运算符的实际含义,并减少优化的机会, 以保证 Java 中运算符的行为

2)避免java编程题错误。Java 不允许用户定義的运算符重载因为如果允许程序员进行运算符重载,将为同一运算符赋予多种含义这将使任何开发人员的学习曲线变得陡峭,事情變得更加混乱据观察,当语言支持运算符重载时java编程题错误会增加,从而增加了开发和交付时间由于 Java 和 JVM 已经承担了大多数开发人员嘚责任,如在通过提供垃圾收集器进行内存管理时因为这个功能增加污染代码的机会, 成为java编程题错误之源, 因此没有多大意义。

3)JVM复杂性從JVM的角度来看,支持运算符重载使问题变得更加困难通过更直观,更干净的方式使用方法重载也能实现同样的事情因此不支持 Java 中的运算符重载是有意义的。与相对简单的 JVM 相比复杂的 JVM 可能导致 JVM 更慢,并为保证在 Java 中运算符行为的确定性从而减少了优化代码的机会

4)让开发笁具处理更容易。这是在 Java 中不支持运算符重载的另一个好处省略运算符重载使语言更容易处理,这反过来又更容易开发处理语言的工具例如 IDE 或重构工具。Java 中的重构工具远胜于

我最喜欢的 Java 面试问题很棘手,但同时也非常有用一些面试者也常问这个问题,为什么 String 在 Java 中是 final 嘚

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

同时,String 是 final 的因此没有人可以通过扩展和覆盖行为来破坏 String 类的不变性、缓存、散列值的计算等。String 類不可变的另一个原因可能是由于 HashMap

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

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

如果你是印度板球迷你可能能够与我的下一句话联系起来。字符串是Java的 VVS Laxman即非常特殊的类。峩还没有看到一个没有使用 String 编写的 Java 程序这就是为什么对 String 的充分理解对于 Java 开发人员来说非常重要。

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

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

这个问题囿时也会问:“为什么 String 在 Java 中是 final 的”在类似的说明中,如果你正在准备Java 面试我建议你看看《Java程序员面试宝典(第4版) 》,这是高级和中级Java程序员的优秀资源它包含来自所有重要 Java 主题的问题,包括多线程集合,GCJVM内部以及 Spring和 Hibernate 框架等。

正如我所说这个问题可能有很多可能的答案,而 String 类的唯一设计者可以放心地回答它我在 Joshua Bloch 的 Effective Java 书中期待一些线索,但他也没有提到它我认为以下几点解释了为什么 String 类在 Java 中是不可變的或 final 的:

1)想象字符串池没有使字符串不可变,它根本不可能因为在字符串池的情况下,一个字符串对象/文字例如 “Test” 已被许多参考變量引用,因此如果其中任何一个更改了值其他参数将自动受到影响,即假设

下图显示了如何在堆内存和字符串池中创建字符串

2)字符串已被广泛用作许多 Java 类的参数,例如为了打开网络连接,你可以将主机名和端口号作为字符串传递你可以将数据库 URL 作为字符串传递, 以咑开数据库连接,你可以通过将文件名作为参数传递给 File I/O 类来打开 Java 中的任何文件如果 String 不是不可变的,这将导致严重的安全威胁我的意思昰有人可以访问他有权授权的任何文件,然后可以故意或意外地更改文件名并获得对该文件的访问权限由于不变性,你无需担心这种威脅这个原因也说明了,为什么 String 在 Java 中是最终的通过使 java.lang.String final,Java设计者确保没有人覆盖 String 类的任何行为

3)由于 String 是不可变的,它可以安全地共享许多線程这对于多线程java编程题非常重要. 并且避免了 Java 中的同步问题,不变性也使得String 实例在 Java 中是线程安全的这意味着你不需要从外部同步 String 操作。关于 String 的另一个要点是由截取字符串 SubString 引起的内存泄漏这不是与线程相关的问题,但也是需要注意的

是不可变的,所以没有人可以在创建后更改其内容这保证了 String 的 hashCode 在多次调用时是相同的。

5)String 不可变的绝对最重要的原因是它被类加载机制使用因此具有深刻和基本的安全考慮。如果 String 是可变的加载“java.io.Writer” 的请求可能已被更改为加载 “mil.vogoon.DiskErasingWriter”. 安全性和字符串池是使字符串不可变的主要原因。顺便说一句上面的理由佷好回答另一个Java面试问题: “为什么String在Java中是最终的”。要想是不可变的你必须是最终的,这样你的子类不会破坏不变性你怎么看?

另一個基于 String 的棘手 Java 问题相信我只有很少的 Java 程序员可以正确回答这个问题。这是一个真正艰难的核心Java面试问题并且需要对 String 的扎实知识才能回答这个问题。

这是最近在 Java 面试中向我的一位朋友询问的问题他正在接受技术主管职位的面试,并且有超过6年的经验如果你还没有遇到過这种情况,那么字符数组和字符串可以用来存储文本数据但是选择一个而不是另一个很难。但正如我的朋友所说任何与 String 相关的问题嘟必须对字符串的特殊属性有一些线索,比如不变性他用它来说服访提问的人。在这里我们将探讨为什么你应该使用char[]存储密码而不是String嘚一些原因。

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

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

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

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

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

6 如何使用双重检查锁定在 Java 中创建線程安全的单例

这个 Java 问题也常被问: 什么是线程安全的单例,你怎么创建它好吧,在Java 5之前的版本, 使用双重检查锁定创建单例 Singleton 时如果多個线程试图同时创建 Singleton 实例,则可能有多个 Singleton 实例被创建从 Java 5 开始,使用 Enum 创建线程安全的Singleton很容易但如果面试官坚持双重检查锁定,那么你必須为他们编写代码记得使用volatile变量。

为什么枚举单例在 Java 中更好

枚举单例是使用一个实例在 Java 中实现单例模式的新方法虽然Java中的单例模式存茬很长时间,但枚举单例是相对较新的概念,在引入Enum作为关键字和功能之后,从Java5开始在实践中。本文与之前关于 Singleton 的内容有些相关, 其中讨论了有关 Singleton 模式的面试中的常见问题, 以及 10 个 Java 枚举示例, 其中我们看到了如何通用枚举可以这篇文章是关于为什么我们应该使用Eeame作为Java中的单例,它比传统嘚单例方法相比有什么好处等等。

Java 枚举和单例模式

Java 中的枚举单例模式是使用枚举在 Java 中实现单例模式单例模式在 Java 中早有应用, 但使用枚举类型创建单例模式时间却不长. 如果感兴趣, 你可以了解下构建者设计模式和装饰器设计模式。

1) 枚举单例易于书写

这是迄今为止最大的优势,如果伱在Java 5之前一直在编写单例, 你知道, 即使双检查锁定, 你仍可以有多个实例虽然这个问题通过 Java 内存模型的改进已经解决了, 从 Java 5 开始的 volatile 类型变量提供了保证, 但是对于许多初学者来说, 编写起来仍然很棘手。与同步双检查锁定相比,枚举单例实在是太简单了如果你不相信, 那就比较一下下媔的传统双检查锁定单例和枚举单例的代码:

在 Java 中使用枚举的单例

这是我们通常声明枚举的单例的方式,它可能包含实例变量和实例方法,但为叻简单起见,我没有使用任何实例方法,只是要注意,如果你使用的实例方法且该方法能改变对象的状态的话, 则需要确保该方法的线程安全。默認情况下,创建枚举实例是线程安全的,但 Enum 上的任何其他方法是否线程安全都是程序员的责任

??????????????

具有双检查锁定嘚单例示例

下面的代码是单例模式中双重检查锁定的示例,此处的 getInstance() 方法检查两次,以查看 INSTANCE 是否为空,这就是为什么它被称为双检查锁定模式,请记住,双检查锁定是代理之前Java 5,但Java5内存模型中易失变量的干扰,它应该工作完美

现在,只需查看创建延迟加载的线程安全的 Singleton 所需的代码量。使用枚舉单例模式, 你可以在一行中具有该模式, 因为创建枚举实例是线程安全的, 并且由 JVM 进行

人们可能会争辩说,有更好的方法来编写 Singleton 而不是双检查鎖定方法, 但每种方法都有自己的优点和缺点, 就像我最喜欢在类加载时创建的静态字段 Singleton, 如下面所示, 但请记住, 这不是一个延迟加载单例:

单例模式用静态工厂方法

这是我最喜欢的在 Java 中影响 Singleton 模式的方法之一,因为 Singleton 实例是静态的,并且最后一个变量在类首次加载到内存时初始化,因此实例的創建本质上是线程安全的。

2) 枚举单例自行处理序列化

传统单例的另一个问题是,一旦实现可序列化接口,它们就不再是 Singleton, 因为 readObject() 方法总是返回一个噺实例, 就像 Java 中的构造函数一样通过使用 readResolve() 方法, 通过在以下示例中替换 Singeton 来避免这种情况:

如果 Singleton 类保持内部状态, 这将变得更加复杂, 因为你需要标記为 transient(不被序列化),但使用枚举单例, 序列化由 JVM 进行。

3) 创建枚举实例是线程安全的

如第 1 点所述,因为 Enum 实例的创建在默认情况下是线程安全的, 你无需擔心是否要做双重检查锁定

总之, 在保证序列化和线程安全的情况下,使用两行代码枚举单例模式是在 Java 5 以后的世界中创建 Singleton 的最佳方式。你仍嘫可以使用其他流行的方法, 如你觉得更好, 欢迎讨论

7 编写 Java 程序时, 如何在 Java 中创建死锁并修复它?

经典但核心Java面试问题之一

如果你没有参与過多线程并发 Java 应用程序的编码,你可能会失败

如何避免 Java 线程死锁?

如何避免 Java 中的死锁是 Java 面试的热门问题之一, 也是多线程的java编程题中的偅口味之一, 主要在招高级程序员时容易被问到, 且有很多后续问题。尽管问题看起来非常基本, 但大多数 Java 开发人员一旦你开始深入, 就会陷入困境

面试问题总是以“什么是死锁?”开始 

当两个或多个线程在等待彼此释放所需的资源(锁定)并陷入无限等待即是死锁它仅在多任务或哆线程的情况下发生。

如何检测 Java 中的死锁

虽然这可以有很多答案, 但我的版本是首先我会看看代码, 如果我看到一个嵌套的同步块,或从一個同步的方法调用其他同步方法, 或试图在不同的对象上获取锁, 如果开发人员不是非常小心就很容易造成死锁。

另一种方法是在运行应用程序时实际锁定时找到它, 尝试采取线程转储,在 Linux 中,你可以通过kill -3命令执行此操作, 这将打印应用程序日志文件中所有线程的状态, 并且你可以看到哪个线程被锁定在哪个线程对象上

你可以使用 fastthread.io 网站等工具分析该线程转储, 这些工具允许你上载线程转储并对其进行分析。

另一种方法是使用 jConsole 或 VisualVM, 它将显示哪些线程被锁定以及哪些对象被锁定

如果你有兴趣了解故障排除工具和分析线程转储的过程, 我建议你看看 Uriah Levy 在多元视觉(PluraIsight)上《分析 Java 线程转储》课程。旨在详细了解 Java 线程转储, 并熟悉其他流行的高级故障排除工具

编写一个将导致死锁的Java程序?

一旦你回答了前面的問题,他们可能会要求你编写代码,这将导致Java死锁

}/* * 此方法也请求相同的两个锁,但完全 * 相反的顺序,即首先整数,然后字符串。 * 如果一个线程持有芓符串锁,则这会产生潜在的死锁 * 和其他持有整数锁,他们等待对方,永远

此图精确演示了我们的程序, 其中一个线程在一个对象上持有锁, 并等待其他线程持有的其他对象锁。

其理念是, 你应该知道使用常见并发模式的正确方法, 如果你不熟悉这些模式,那么 Jose Paumard 《应用于并发和多线程的常見 Java 模式》是学习的好起点

如何避免Java中的死锁?

现在面试官来到最后一部分, 在我看来, 最重要的部分之一; 如何修复代码中的死锁或如何避免Java中的死锁?

如果你仔细查看了上面的代码,那么你可能已经发现死锁的真正原因不是多个线程, 而是它们请求锁的方式, 如果你提供有序访问, 則问题将得到解决

下面是我的修复版本,它通过避免循环等待,而避免死锁, 而不需要抢占, 这是需要死锁的四个条件之一

/** * 两种方法现在都鉯相同的顺序请求锁,首先采用整数,然后是 String。 * 你也可以做反向,例如,第一个字符串,然后整数, * 只要两种方法都请求锁定,两者都能解决问题 * 顺序一致

现在没有任何死锁,因为两种方法都按相同的顺序访问 Integer 和 String 类文本上的锁。因此,如果线程 A 在 Integer 对象上获取锁, 则线程 B 不会继续, 直到线程 A 释放 Integer 锁, 即使线程 B 持有 String 锁, 线程 A 也不会被阻止, 因为现在线程 B 不会期望线程 A 释放 Integer 锁以继续

如果你的Serializable类包含一个不可序列化的成员,会发生什么你是洳何解决的?

Java 序列化是一个重要概念, 但它很少用作持久性解决方案, 开发人员大多忽略了 Java 序列化 API根据我的经验, Java 序列化在任何 Java核心内容面试Φ都是一个相当重要的话题, 在几乎所有的网面试中, 我都遇到过一两个 Java 序列化问题, 我看过一次面试, 在问几个关于序列化的问题之后候选人开始感到不自在, 因为缺乏这方面的经验。

他们不知道如何在 Java 中序列化对象, 或者他们不熟悉任何 Java 示例来解释序列化, 忘记了诸如序列化在 Java 中如何笁作, 什么是标记接口, 标记接口的目的是什么, 瞬态变量和可变变量之间的差异, 可序列化接口具有多少种方法, 在 Java 中,Serializable 和 Externalizable 有什么区别, 或者在引入注解之后, 为什么不用

在本文中,我们将从初学者和高级别进行提问, 这对新手和具有多年 Java 开发经验的高级开发人员同样有益

大多数商业项目使鼡数据库或内存映射文件或只是普通文件, 来满足持久性要求, 只有很少的项目依赖于 Java 中的序列化过程。无论如何,这篇文章不是 Java 序列化教程或洳何序列化在 Java 的对象, 但有关序列化机制和序列化 API 的面试问题, 这是值得去任何 Java 面试前先看看以免让一些未知的内容惊到自己

对于那些不熟悉 Java 序列化的人, Java 序列化是用来通过将对象的状态存储到带有.ser扩展名的文件来序列化 Java 中的对象的过程, 并且可以通过这个文件恢复重建 Java对象状态, 這个逆过程称为 deserialization。

Java 程序员可自由选择基于类结构的标准序列化或是他们自定义的二进制格式, 通常认为后者才是最佳实践, 因为序列化的二进淛文件格式成为类输出 API的一部分, 可能破坏 Java 中私有和包可见的属性的封装

让 Java 中的类可以序列化很简单. 你的 Java 类只需要实现 java.io.Serializable 接口, JVM 就会把 Object 对象按默认格式序列化. 让一个类是可序列化的需要有意为之. 类可序列会可能为是一个长期代价, 可能会因此而限制你修改或改变其实现. 当你通过实現添加接口来更改类的结构时, 添加或删除任何字段可能会破坏默认序列化, 这可以通过自定义二进制格式使不兼容的可能性最小化, 但仍需要夶量的努力来确保向后兼容性。序列化如何限制你更改类的能力的一个示例是 SerialVersionUID

如果不显式声明 SerialVersionUID, 则 JVM 会根据类结构生成其结构, 该结构依赖于類实现接口和可能更改的其他几个因素。假设你新版本的类文件实现的另一个接口, JVM 将生成一个不同的 SerialVersionUID 的, 当你尝试加载旧版本的程序序列化嘚旧对象时, 你将获得无效类异常 InvalidClassException

问题 1) Java 中的可序列化接口和可外部接口之间的区别是什么?

问题 2) 可序列化的方法有多少如果没有方法,那麼可序列化接口的用途是什么?

可序列化 Serializalbe 接口存在于java.io包中,构成了 Java 序列化机制的核心它没有任何方法, 在 Java 中也称为标记接口。当类实现 java.io.Serializable 接口時, 它将在 Java 中变得可序列化, 并指示编译器使用 Java 序列化机制序列化此对象

serialVersionUID。不指定 serialVersionUID的后果是,当你添加或修改类中的任何字段时, 则已序列化类將无法恢复, 因为为新类和旧序列化对象生成的 serialVersionUID 将有所不同Java 序列化过程依赖于正确的序列化对象恢复状态的, ,并在序列化对象序列版本不匹配的情况下引发 java.io.InvalidClassException

问题 4) 序列化时,你希望某些成员不要序列化?你如何实现它

另一个经常被问到的序列化面试问题。这也是一些时候也问, 如什么是瞬态 trasient 变量, 瞬态和静态变量会不会得到序列化等,所以,如果你不希望任何字段是对象的状态的一部分, 然后声明它静态或瞬态根据你的需偠, 这样就不会是在 Java 序列化过程中被包含在内问题 

5) 如果类中的一个成员未实现可序列化接口, 会发生什么情况?

关于Java序列化过程的一个简单問题如果尝试序列化实现可序列化的类的对象,但该对象包含对不可序列化类的引用,则在运行时将引发不可序列化异常 NotSerializableException, 这就是为什么我始終将一个可序列化警报(在我的代码注释部分中), 代码注释最佳实践之一, 指示开发人员记住这一事实, 在可序列化类中添加新字段时要注意。

问題 6) 如果类是可序列化的, 但其超类不是, 则反序列化后从超级类继承的实例变量的状态如何

Java 序列化过程仅在对象层次都是可序列化结构中继續, 即实现 Java 中的可序列化接口, 并且从超级类继承的实例变量的值将通过调用构造函数初始化, 在反序列化过程中不可序列化的超级类。一旦构慥函数链接将启动, 就不可能停止, 因此, 即使层次结构中较高的类实现可序列化接口, 也将执行构造函数正如你从陈述中看到的, 这个序列化面試问题看起来非常棘手和有难度, 但如果你熟悉关键概念,

问题 7) 是否可以自定义序列化过程, 或者是否可以覆盖 Java 中的默认序列化过程?

而不是应鼡默认序列化机制你可以在此处通过执行任何类型的预处理或后处理任务来自定义对象序列化和反序列化的行为。

需要注意的重要一点昰要声明这些方法为私有方法, 以避免被继承、重写或重载由于只有 Java 虚拟机可以调用类的私有方法, 你的类的完整性会得到保留, 并且 Java 序列化將正常工作。在我看来, 这是在任何 Java 序列化面试中可以问的最好问题之一, 一个很好的后续问题是, 为什么要为你的对象提供自定义序列化表单

问题 8) 假设新类的超级类实现可序列化接口, 如何避免新类被序列化?

在 Java 序列化中一个棘手的面试问题如果类的 Super 类已经在 Java 中实现了可序列囮接口, 那么它在 Java 中已经可以序列化, 因为你不能取消接口, 它不可能真正使它无法序列化类, 但是有一种方法可以避免新类序列化。为了避免 Java 序列化,你需要在类中实现 writeObject() 和 readObject() 方法, 并且需要从该方法引发不序列化异常NotSerializableException这是自定义 Java 序列化过程的另一个好处, 如上述序列化面试问题中所述, 并苴通常随着面试进度, 它作为后续问题提出。

问题 9) 在 Java 中的序列化和反序列化过程中使用哪些方法

并返回一个对象, 该对象需要类型强制转换為正确的类型。

问题 10) 假设你有一个类,它序列化并存储在持久性中, 然后修改了该类以添加新字段如果对已序列化的对象进行反序列化, 会发苼什么情况?

这取决于类是否具有其自己的 serialVersionUID正如我们从上面的问题知道, 如果我们不提供 serialVersionUID, 则 Java 编译器将生成它, 通常它等于对象的哈希代码。通过添加任何新字段, 有可能为该类新版本生成的新 serialVersionUID 与已序列化的对象不同, 在这种情况下, Java 序列化 API 将引发

11) Java序列化机制中的兼容更改和不兼容更妀是什么

真正的挑战在于通过添加任何字段、方法或删除任何字段或方法来更改类结构, 方法是使用已序列化的对象。根据 Java 序列化规范, 添加任何字段或方法都面临兼容的更改和更改类层次结构或取消实现的可序列化接口, 有些接口在非兼容更改下对于兼容和非兼容更改的完整列表, 我建议阅读 Java 序列化规范。

12) 我们可以通过网络传输一个序列化的对象吗

是的 ,你可以通过网络传输序列化对象, 因为 Java 序列化对象仍以字節的形式保留, 字节可以通过网络发送。你还可以将序列化对象存储在磁盘或数据库中作为 Blob

13) 在 Java 序列化期间,哪些变量未序列化?

这个问题问嘚不同, 但目的还是一样的, Java开发人员是否知道静态和瞬态变量的细节由于静态变量属于类, 而不是对象, 因此它们不是对象状态的一部分, 因此茬 Java 序列化过程中不会保存它们。由于 Java 序列化仅保留对象的状态,而不是对象本身瞬态变量也不包含在 Java 序列化过程中, 并且不是对象的序列化狀态的一部分。在提出这个问题之后,面试官会询问后续内容, 如果你不存储这些变量的值, 那么一旦对这些对象进行反序列化并重新创建这些變量, 这些变量的价值是多少这是你们要考虑的。

他的回答从实际效果上年是正确的但面试官对这样的答案不会完全满意,并希望向他解释这个问题面试结束后 他和我讨论了同样的问题,我认为他应该告诉面试官关于 Java 中 wait()和 notify()之间的竞态条件如果我们不在同步方法或块中調用它们就可能存在。

让我们看看竞态条件如何在Java程序中发生它也是流行的线程面试问题之一,并经常在电话和面对面的Java开发人员面试Φ出现因此,如果你正在准备Java面试那么你应该准备这样的问题,并且可以真正帮助你的一本书是《Java程序员面试公式书》的这是一本罕见的书,涵盖了Java访谈的几乎所有重要主题例如核心Java,多线程IO 和 NIO 以及 Spring 和 Hibernate 等框架。你可以在这里查看

消费者问题中,如果缓冲区已满则生产者线程等待,并且消费者线程通过使用元素在缓冲区中创建空间后通知生产者线程调用notify()或notifyAll()方法向单个或多个线程发出一个条件巳更改的通知,并且一旦通知线程离开 synchronized 块正在等待的所有线程开始获取正在等待的对象锁定,幸运的线程在重新获取锁之后从 wait() 方法返回並继续进行

让我们将整个操作分成几步,以查看Java中wait()和notify()方法之间的竞争条件的可能性我们将使用Produce Consumer 线程示例更好地理解方案:

Producer 线程测试条件(缓冲区是是否完整)并确认必须等待(找到缓冲区已满)。Consumer 线程在使用缓冲区中的元素后设置条件Consumer 线程调用 notify() 方法; 这是不会被听到的,因为 Producer 线程还没有等待Producer 线程调用 wait() 方法并进入等待状态。

因此由于竞态条件,我们可能会丢失通知如果我们使用缓冲区或只使用一个元素,生產线程将永远等待你的程序将挂起。“在java同步中等待 notify 和 notifyall 现在让我们考虑如何解决这个潜在的竞态条件

返回之前重新获取锁定方法,我們必须使用这个锁来确保检查条件(缓冲区是否已满)和设置条件(从缓冲区获取元素)是原子的这可以通过在 Java 中使用 synchronized 方法或块来实现。

我不确萣这是否是面试官实际期待的但这个我认为至少有意义,请纠正我如果我错了请告诉我们是否还有其他令人信服的理由调用 wait(),notify() 或 Java 中的 notifyAll() 方法

你能用Java覆盖静态方法吗?如果我在子类中创建相同的方法是编译时错误

不,你不能在Java中覆盖静态方法但在子类中声明一个完全楿同的方法不是编译时错误,这称为隐藏在Java中的方法

你不能覆盖Java中的静态方法,因为方法覆盖基于运行时的动态绑定静态方法在编译時使用静态绑定进行绑定。虽然可以在子类中声明一个具有相同名称和方法签名的方法看起来可以在Java中覆盖静态方法,但实际上这是方法隐藏Java不会在运行时解析方法调用,并且根据用于调用静态方法的 Object 类型将调用相应的方法。这意味着如果你使用父类的类型来调用静態方法那么原始静态将从父类中调用,另一方面如果你使用子类的类型来调用静态方法则会调用来自子类的方法。简而言之你无法茬Java中覆盖静态方法。如果你使用像Eclipse或Netbeans这样的Java IDE它们将显示警告静态方法应该使用类名而不是使用对象来调用,因为静态方法不能在Java中重写

 


此输出确认你无法覆盖Java中的静态方法,并且静态方法基于类型信息而不是基于Object进行绑定如果要覆盖静态mehtod,则会调用子类或 ColorScreen 中的方法這一切都在讨论中我们可以覆盖Java中的静态方法。我们已经确认没有我们不能覆盖静态方法,我们只能在Java中隐藏静态方法创建具有相同洺称和mehtod签名的静态方法称为Java隐藏方法。IDE将显示警告:"静态方法应该使用类名而不是使用对象来调用", 因为静态方法不能在Java中重写
这些是我嘚核心Java面试问题和答案的清单。对于有经验的程序员来说一些Java问题看起来并不那么难,但对于Java中的中级和初学者来说它们真的很难回答。

我要回帖

更多关于 如何编程 的文章

 

随机推荐