我怀疑我遇到过阅读Effective Java.如果它是一个真正简单而直截了当的疑问,我道歉.因此,在第74项 - 明智地实施Serializable中,他说,即使在使用私有和私有领域实施一个好的信息隐藏在你的班级之后,它也很容易失去效力?无论我过去阅读过什么,所有序列化都是将对象转换为字节流形式,反序列化后保留相同的对象.如何在此过程中丢失数据隐藏?
我正在阅读关于双重检查锁定的信息Effective Java.代码执行以下操作:
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) { // First check (no locking)
synchronized(this) {
result = field;
if (result == null) // Second check (with locking)
field = result = computeFieldValue();
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
它说使用result似乎不需要但实际上确保field只在已经初始化的常见情况下只读取一次.
但我不明白这一点.与if(field == null)直接做什么有什么区别?我不明白为什么if (result == null)会有所不同,更不用说如上所述了.
java concurrency multithreading synchronization effective-java
有效的java书的第74号项目有一个段落(项目74的最后一个第2段),如下所述:
内部类(第22项)不应实现Serializable.它们使用编译器生成的合成字段来存储对封闭实例的引用,并存储来自封闭范围的局部变量的值.这些字段如何对应于类定义是未指定的,匿名和本地类的名称也是如此. 因此,内部类的默认序列化形式是不明确的.
我知道内部类使用编译器生成的合成字段来存储对封闭实例的引用,例如,如果封闭类是MyEnclosing而内部类是MyInner,则封闭引用是MyEnclosing.this.但我无法获得BOLD部分.请帮我理解意思.谢谢!!!
我知道只要equals在Java中重写该方法,就需要重写哈希码。那仅仅是合同。我试图了解其背后的逻辑。我正在阅读Joshua Bloch的 * Effective Java ,发现了以下代码(第9页,第45页):
import java.util.HashMap;
import java.util.Map;
public final class PhoneNumber {
private final short areaCode;
private final short prefix;
private final short lineNumber;
public PhoneNumber(int areaCode, int prefix, int lineNumber) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(prefix, 999, "prefix");
rangeCheck(lineNumber, 9999, "line number");
this.areaCode = (short) areaCode;
this.prefix = (short) prefix;
this.lineNumber = (short) lineNumber;
}
private static void rangeCheck(int arg, int max, String name) {
if (arg < 0 || arg > max) …Run Code Online (Sandbox Code Playgroud) 我有两个相关的问题:
按位运算符>>>表示我们正在将二进制数转移多个位置,同时在最高位填充0.但是,为什么以下操作产生相同的数字:5 >>> 32产生5和-5 >>> 32产生-5.因为如果上面的描述是正确的,那么这两个操作都会产生0作为最终结果.
在上面的继续中,根据Effective Java book,我们应该在计算哈希码时使用(int)(f ^(f >>> 32))(如果字段很长)(如果字段很长).为什么我们这样做,解释是什么
阅读Effective Java,我从Item 16: Favor composition over inheritance.
在下面InstrumentedSet,这本书显示我们可以跟踪元素被插入的次数(通过InstrumentedSet.addCount变量)。
要做到这一点,我们可以简单地附加到这个类对象的addCount,然后调用ForwardingSet.add(),它调用实际Set类的 实际实现add()。
// Reusable forwarding class
public class ForwardingSet<E> implements Set<E> {
private final Set<E> s;
public ForwardingSet(Set<E> s) { this.s = s; }
public void clear() { s.clear(); }
public boolean contains(Object o) { return s.contains(o); }
...
}
// Wrapper class - uses composition in place of inheritance
public class InstrumentedSet<E> extends ForwardingSet<E> { …Run Code Online (Sandbox Code Playgroud) JavaBean 在其构造过程中可能会处于不一致的状态。
我无法理解这一点,如果在方法中构造一个对象,那么它会如何不一致,如果必须发生异常,那么也可能在构造函数中发生。这与线程有何关系?
在新的第三版Effective Java中,Joshua Bloch提到了Java Puzzlers的一段代码(它是关于在try-finally中关闭资源):
对于初学者来说,我在Java Puzzlers的第88页上弄错了,多年来没有人注意到.事实上,2007年Java库中close方法的三分之二使用是错误的.
但我不确定哪个部分错了?
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
// There is nothing we can do if close fails
}
}
if (out != null) {
try {
out.close();
} catch (IOException ex) {
// Again, there is nothing we can do if close fails
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是此代码的新版本:
try {
OutputStream out = new FileOutputStream(dst);
try {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while …Run Code Online (Sandbox Code Playgroud) 在《Effective Java》(第三版)第 56 条中,Joshua Bloch 指出:“公共类不应该使用默认构造函数,因为没有办法为它们提供文档注释。”
默认构造函数不会做任何意外的事情,但它只是创建一个新实例。什么样的信息应该记录在无参数构造函数的文档注释中,而这些信息不应该只存在于类注释中?
如果一个类在初始化块中具有有趣的行为(因为否则没有地方可以对它们进行注释),或者甚至是字段的非标准值分配(可能调用方法来获取初始值),我可以理解这样做。但对于大多数课程来说,这似乎并没有增加太多。我有什么遗漏的吗?
不幸的是,Effective Java 中没有任何文章讨论保留类型名称“var”(因为它是在 java 10 中引入的)。
有一种说法是,尽可能使用接口作为类型(条款 64:通过接口引用对象)。但是使用时var:
var list = new ArrayList<String>(); // infers ArrayList<String>
(list属于类型ArrayList<String>)
《Effective Java》指出,通过变量的实现来引用变量是一种不好的做法,因为它会使代码依赖于它。这只是我在代码中开始使用 var 时发现的一个烦恼。
使用保留类型名称“var”时是否有任何最佳实践?我什么时候应该使用它?我什么时候应该避免它?
effective-java ×10
java ×10
hashcode ×2
concurrency ×1
equals ×1
gethashcode ×1
java-10 ×1
object ×1
try-catch ×1
try-finally ×1
var ×1