1、为什么等待和通知是在 Object 类而不是 Thread 中声明的?
5、为什么 char 数组比 Java 中的 String 更适合存储密码?
6、如何使用双重检查锁定在 Java 中创建线程安全的单例?
7、编写 Java 程序时, 如何在 Java 中创建死锁并修复它?
8、如果你的Serializable类包含一个不可序列化的成员,会发生什么?你是如何解决的?
9、为什么Java中 wait 方法需要在 synchronized 的方法中调用?
10、你能用Java覆盖静态方法吗?如果我在子类中创建相同的方法是编译时错误?
本文转自:公众号JAVA https://mp.weixin.qq.com/s/EZPc2tO8WX6fV2iag70how
想要获取更多技术干货,钉钉扫码,关注阿里云开发者社群
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
这些问题涉及Java编程语言的多个方面,包括设计决策、语言特性、并发编程和对象序列化等。下面我将基于阿里云开发者社群的知识库来回答这些问题:
为什么等待和通知是在 Object 类而不是 Thread 中声明的? 等待(wait)、通知(notify/notifyAll)方法在 Object
类中定义是因为它们与对象的状态和同步有关,而非线程本身的行为。这些方法通常与 synchronized 块或方法一起使用,以控制对共享资源的访问。通过在 Object
上实现,任何对象都可以成为线程间通信的媒介。
为什么Java中不支持多重继承? Java 不支持多重继承是为了简化语言设计,避免“菱形问题”(diamond problem),即当一个类继承自多个具有相同方法签名的基类时,会产生调用哪个基类方法的不确定性。Java 通过接口(Interface)提供了一种实现多重继承功能的替代方案,允许类实现多个接口,从而达到类似的效果但避免了潜在的冲突。
为什么Java不支持运算符重载? Java 设计者选择不支持运算符重载主要是为了保持语言的简洁性和易读性。运算符重载可能导致代码难以理解,尤其是在没有明确上下文的情况下。Java 鼓励使用方法命名来清晰表达操作意图,比如 add()
而不是重载 +
运算符。
为什么 String 在 Java 中是不可变的? String
的不可变性保证了线程安全,一旦创建,其内容就不能改变,这使得字符串可以被多个线程安全地共享。此外,不可变性还有利于缓存和哈希码的一致性,以及作为键值(如在 HashMap 中)的安全性。
为什么 char 数组比 Java 中的 String 更适合存储密码? 使用 char 数组存储密码比直接使用 String 更安全,因为 String 对象可能保存在内存中较长时间,且可能被垃圾回收机制以外的方式访问到。而 char 数组可以在使用后立即清零,减少敏感信息泄露的风险。
如何使用双重检查锁定在 Java 中创建线程安全的单例? 双重检查锁定模式是一种优化,用于减少获取单例实例时的同步开销。基本思路是:在获取实例前先检查实例是否已创建,如果未创建,再进行同步并再次检查实例状态,确保只有一个线程能够创建实例。
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
编写 Java 程序时, 如何在 Java 中创建死锁并修复它? 创建死锁通常涉及两个或更多线程,每个线程持有至少一个锁,并尝试获取对方已经持有的锁。修复死锁通常需要避免循环等待条件,可以通过按顺序加锁、设置锁的超时或者使用高级并发工具(如 java.util.concurrent
包中的工具)来解决。
如果你的Serializable类包含一个不可序列化的成员,会发生什么?你是如何解决的? 如果 Serializable
类包含不可序列化的成员,序列化该对象时会抛出 NotSerializableException
。解决方法之一是使用 transient
关键字标记不可序列化的成员,这样在序列化时会被忽略。对于复杂情况,可以实现 writeObject
和 readObject
方法来自定义序列化和反序列化过程。
为什么Java中 wait 方法需要在 synchronized 的方法中调用? wait()
方法必须在同步块或方法中调用,因为它依赖于对象监视器(monitor)。只有获得了对象的锁,线程才能调用 wait()
,释放锁并进入等待状态。这样做可以确保线程之间的协调是安全的,防止竞态条件。
你能用Java覆盖静态方法吗?如果我在子类中创建相同的方法是编译时错误? Java 不允许覆盖静态方法。如果在子类中定义了一个与父类同名的静态方法,这不是覆盖,而是隐藏。这意味着,根据引用类型的不同,调用的是不同版本的静态方法。这不是编译时错误,但需要注意这种行为可能会导致代码可读性和维护性的降低。正确的做法是尽量避免这种做法,考虑使用多态或设计模式来改善代码结构。