中⾼级Java开发⾯试题,最难的⼏道Java⾯试题,看看你跪在第⼏个
5.为什么 char 数组⽐ Java 中的 String 更适合存储密码?
另⼀个基于 String 的棘⼿ Java 问题,相信我只有很少的 Java 程序员可以正确回答这个问题。这是⼀个真正艰难的核⼼Java⾯试问题,并且需要对 String 的扎实知识才能回答这个问题。
这是最近在 Java ⾯试中向我的⼀位朋友询问的问题。他正在接受技术主管职位的⾯试,并且有超过6年的经验。如果你还没有遇到过这种情况,那么字符数组和字符串可以⽤来存储⽂本数据,但是选择⼀个⽽不是另⼀个很难。但正如我的朋友所说,任何与 String 相关的问题都必须对字符串的特殊属性有⼀些线索,⽐如不变性,他⽤它来说服访提问的⼈。在这⾥,我们将探讨为什么你应该使⽤char[]存储密码⽽不是String的⼀些原因。
字符串:
1)由于字符串在 Java 中是不可变的,如果你将密码存储为纯⽂本,它将在内存中可⽤,直到垃圾收集器清除它. 并且为了可重⽤性,会存在 String 在字符串池中, 它很可能会保留在内存中持续很长时间,从⽽构成安全威胁。
由于任何有权访问内存转储的⼈都可以以明⽂形式到密码,这是另⼀个原因,你应该始终使⽤加密密码
⽽不是纯⽂本。由于字符串是不可变的,所以不能更改字符串的内容,因为任何更改都会产⽣新的字符串,⽽如果你使⽤char[],你就可以将所有元素设置为空⽩或零。因此,在字符数组中存储密码可以明显降低窃取密码的安全风险。
2)Java 本⾝建议使⽤ JPasswordField 的 getPassword() ⽅法,该⽅法返回⼀个 char[] 和不推荐使⽤的getTex() ⽅法,该⽅法以明⽂形式返回密码,由于安全原因。应遵循 Java 团队的建议, 坚持标准⽽不是反对它。
3)使⽤ String 时,总是存在在⽇志⽂件或控制台中打印纯⽂本的风险,但如果使⽤ Array,则不会打印数组的内容⽽是打印其内存位置。虽然不是⼀个真正的原因,但仍然有道理。
String strPassword =“Unknown”;
char [] charPassword = new char [] {'U','n','k','w','o','n'};
System.out.println(“字符密码:”+ strPassword);
System.out.println(“字符密码:”+ charPassword);
输出
字符串密码:Unknown
字符密码:[C @110b053
我还建议使⽤散列或加密的密码⽽不是纯⽂本,并在验证完成后⽴即从内存中清除它。因此,在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 上的任何其他⽅法是否线程安全都
是程序员的责任。
/**
* 使⽤ Java 枚举的单例模式⽰例
*/
public enum EasySingleton{
INSTANCE;
}
你可以通过EasySingleton.INSTANCE来处理它,这⽐在单例上调⽤getInstance()⽅法容易得多。
具有双检查锁定的单例⽰例
下⾯的代码是单例模式中双重检查锁定的⽰例,此处的getInstance() ⽅法检查两次,以查看 INSTANCE 是否为空,这就是为什么它被称为双检查锁定模式,请记住,双检查锁定是代理之前Java 5,但Java5内存模型中易失变量的⼲扰,它应该⼯作完美。
/**
* 单例模式⽰例,双重锁定检查
*/
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;
}
}
你可以调⽤Instance() 来获取此单例类的访问权限。
现在,只需查看创建延迟加载的线程安全的 Singleton 所需的代码量。使⽤枚举单例模式, 你可以在⼀⾏中具有该模式, 因为创建枚举实例是线程安全的, 并且由 JVM 进⾏。
⼈们可能会争辩说,有更好的⽅法来编写 Singleton ⽽不是双检查锁定⽅法, 但每种⽅法都有⾃⼰的优点和缺点, 就像我最喜欢在类加载时创建的静态字段 Singleton, 如下⾯所⽰, 但请记住, 这不是⼀个延迟加
载单例:
想要资料的话也可以,免费获取。
⾯试专题⽂档。
7. 编写 Java 程序时, 如何在 Java 中创建死锁并修复它?
经典但核⼼Java⾯试问题之⼀。
如果你没有参与过多线程并发 Java 应⽤程序的编码,你可能会失败。
如何避免 Java 线程死锁?
如何避免 Java 中的死锁?是 Java ⾯试的热门问题之⼀, 也是多线程的编程中的重⼝味之⼀, 主要在招⾼级程序员时容易被问到, 且有很多后续问题。尽管问题看起来⾮常基本, 但⼤多数 Java 开发⼈员⼀旦你开始深⼊, 就会陷⼊困境。
⾯试问题总是以“什么是死锁?”开始
当两个或多个线程在等待彼此释放所需的资源(锁定)并陷⼊⽆限等待即是死锁。它仅在多任务或多线程的情况下发⽣。
如何检测 Java 中的死锁?
虽然这可以有很多答案, 但我的版本是⾸先我会看看代码, 如果我看到⼀个嵌套的同步块,或从⼀个同步的⽅法调⽤其他同步⽅法, 或试图在不同的对象上获取锁, 如果开发⼈员不是⾮常⼩⼼,就很容易造成死锁。
另⼀种⽅法是在运⾏应⽤程序时实际锁定时到它, 尝试采取线程转储,在 Linux 中,你可以通过kill -3命令执⾏此操作, 这将打印应⽤程序⽇志⽂件中所有线程的状态, 并且你可以看到哪个线程被锁定在哪个线程对象上。
你可以使⽤ fastthread.io ⽹站等⼯具分析该线程转储, 这些⼯具允许你上载线程转储并对其进⾏分析。
另⼀种⽅法是使⽤ jConsole 或 VisualVM, 它将显⽰哪些线程被锁定以及哪些对象被锁定。
如果你有兴趣了解故障排除⼯具和分析线程转储的过程, 我建议你看看 Uriah Levy 在多元视觉(PluraIsight)上《分析 Java 线程转储》课程。旨在详细了解 Java 线程转储, 并熟悉其他流⾏的⾼级故障排除⼯具。
8. 如果你的Serializable类包含⼀个不可序列化的成员,会发⽣什么?你是如何解决的?
任何序列化该类的尝试都会因NotSerializableException⽽失败,但这可以通过在 Java中 为 static 设置瞬态(trancient)变量来轻松解决。
Java 序列化相关的常见问题
jvm面试题总结及答案Java 序列化是⼀个重要概念, 但它很少⽤作持久性解决⽅案, 开发⼈员⼤多忽略了 Java 序列化 API。根据我的经验, Java 序列化在任何Java核⼼内容⾯试中都是⼀个相当重要的话题, 在⼏乎所有的⽹⾯试中, 我都遇到过⼀两个 Java 序列化问题, 我看过⼀次⾯试, 在问⼏个关于序列化的问题之后候选⼈开始感到不⾃在, 因为缺乏这⽅⾯的经验。
他们不知道如何在 Java 中序列化对象, 或者他们不熟悉任何 Java ⽰例来解释序列化, 忘记了诸如序列化在 Java 中如何⼯作, 什么是标记接⼝, 标记接⼝的⽬的是什么, 瞬态变量和可变变量之间的差异, 可序列化接⼝具有多少种⽅法, 在 Java 中,Serializable 和 Externalizable 有什么区别, 或者在引⼊注解之后, 为什么不⽤ @Serializable 注解或替换 Serializalbe 接⼝。
在本⽂中,我们将从初学者和⾼级别进⾏提问, 这对新⼿和具有多年 Java 开发经验的⾼级开发⼈员同样
有益。
9. 为什么Java中 wait ⽅法需要在 synchronized 的⽅法中调⽤?
另⼀个棘⼿的核⼼ Java 问题,wait 和 notify。它们是在有 synchronized 标记的⽅法或 synchronized 块中调⽤的,因为 wait 和modify 需要监视对其上调⽤ wait 或 notify-get 的 Object。
⼤多数Java开发⼈员都知道对象类的 wait(),notify() 和 notifyAll()⽅法必须在Java中的 synchronized ⽅法或 synchronized 块中调⽤,但是我们想过多少次, 为什么在 Java 中 wait, notify 和 notifyAll 来⾃ synchronized 块或⽅法?
最近这个问题在Java⾯试中被问到我的⼀位朋友,他思索了⼀下,并回答说: 如果我们不从同步上下⽂中调⽤ wait() 或 notify() ⽅法,我们将在 Java 中收到 IllegalMonitorStateException。
他的回答从实际效果上年是正确的,但⾯试官对这样的答案不会完全满意,并希望向他解释这个问题。⾯试结束后 他和我讨论了同样的问题,我认为他应该告诉⾯试官关于 Java 中 wait()和 notify()之间的竞态条件,如果我们不在同步⽅法或块中调⽤它们就可能存在。
让我们看看竞态条件如何在Java程序中发⽣。它也是流⾏的线程⾯试问题之⼀,并经常在电话和⾯对⾯的Java开发⼈员⾯试中出现。因此,如果你正在准备Java⾯试,那么你应该准备这样的问题,并且可以
真正帮助你的⼀本书是《Java程序员⾯试公式书》的。这是⼀本罕见的书,涵盖了Java访谈的⼏乎所有重要主题,例如核⼼Java,多线程,IO 和 NIO 以及 Spring 和 Hibernate 等框架。你可以在这⾥查看。
为什么要等待来⾃ Java中的 synchronized ⽅法的 wait⽅法为什么必须从 Java 中的 synchronized 块或⽅法调⽤ ?我们主要使⽤
wait(),notify() 或 notifyAll() ⽅法⽤于 Java 中的线程间通信。⼀个线程在检查条件后正在等待,例如,在经典的⽣产者 - 消费者问题中,如果缓冲区已满,则⽣产者线程等待,并且消费者线程通过使⽤元素在缓冲区中创建空间后通知⽣产者线程。调⽤notify()或
notifyAll()⽅法向单个或多个线程发出⼀个条件已更改的通知,并且⼀旦通知线程离开 synchronized 块,正在等待的所有线程开始获取正在等待的对象锁定,幸运的线程在重新获取锁之后从 wait() ⽅法返回并继续进⾏。
让我们将整个操作分成⼏步,以查看Java中wait()和notify()⽅法之间的竞争条件的可能性,我们将使⽤Produce Consumer 线程⽰例更好地理解⽅案:
Producer 线程测试条件(缓冲区是是否完整)并确认必须等待(到缓冲区已满)。
Consumer 线程在使⽤缓冲区中的元素后设置条件。
Consumer 线程调⽤ notify() ⽅法; 这是不会被听到的,因为 Producer 线程还没有等待。
Producer 线程调⽤ wait() ⽅法并进⼊等待状态。
因此,由于竞态条件,我们可能会丢失通知,如果我们使⽤缓冲区或只使⽤⼀个元素,⽣产线程将永远等待,你的程序将挂起。“在java同步中等待 notify 和 notifyall 现在让我们考虑如何解决这个潜在的竞态条件?
这个竞态条件通过使⽤ Java 提供的 synchronized 关键字和锁定来解决。为了调⽤ wait(),notify() 或 notifyAll(), 在Java中,我们必须获得对我们调⽤⽅法的对象的锁定。由于 Java 中的 wait() ⽅法在等待之前释放锁定并在从 wait() 返回之前重新获取锁定⽅法,我们必须使⽤这个锁来确保检查条件(缓冲区是否已满)和设置条件(从缓冲区获取元素)是原⼦的,这可以通过在 Java 中使⽤ synchronized ⽅法或块来实现。
我不确定这是否是⾯试官实际期待的,但这个我认为⾄少有意义,请纠正我如果我错了,请告诉我们是否还有其他令⼈信服的理由调⽤
wait(),notify() 或 Java 中的 notifyAll() ⽅法。
总结⼀下,我们⽤ Java 中的 synchronized ⽅法或 synchronized 块调⽤ Java 中的 wait(),notify() 或 notifyAll() ⽅法来避免:
1. Java 会抛出 IllegalMonitorStateException,如果我们不调⽤来⾃同步上下⽂的wait(),notify()或者notifyAll()⽅法。
2. Javac 中 wait 和 notify ⽅法之间的任何潜在竞争条件。
10.你能⽤Java覆盖静态⽅法吗?如果我在⼦类中创建相同的⽅法是编译时错误?
不,你不能在Java中覆盖静态⽅法,但在⼦类中声明⼀个完全相同的⽅法不是编译时错误,这称为隐藏在Java中的⽅法。
你不能覆盖Java中的静态⽅法,因为⽅法覆盖基于运⾏时的动态绑定,静态⽅法在编译时使⽤静态绑定进⾏绑定。虽然可以在⼦类中声明⼀个具有相同名称和⽅法签名的⽅法,看起来可以在Java中覆盖静态⽅法,但实际上这是⽅法隐藏。Java不会在运⾏时解析⽅法调⽤,并且根据⽤于调⽤静态⽅法的 Object 类型,将调⽤相应的⽅法。这意味着如果你使⽤⽗类的类型来调⽤静态⽅法,那么原始静态将从⽗类中调⽤,另⼀⽅⾯如果你使⽤⼦类的类型来调⽤静态⽅法,则会调⽤来⾃⼦类的⽅法。简⽽⾔之,你⽆法在Java中覆盖静态⽅法。如果你使⽤像Eclipse或Netbeans这样的Java IDE,它们将显⽰警告静态⽅法应该使⽤类名⽽不是使⽤对象来调⽤,因为静态⽅法不能在Java中重写。
/**
*
* 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

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。