Bloch的精彩书籍"Effective Java"指出,如果equals不对称,则Collections的行为contains是不确定的.
在他给出的例子中(通过下面的小修改再现),布洛赫说他看到了"假",但也可以看到真实或异常.
如果标准没有指定contains(Object o)检查e.equals(o)或o.equals(e)集合中的每个项目以及前者是否已实现,则可以看到"true" .然而,Collections Javadoc明确指出它必须是后者(这是我观察到的).
所以我看到的唯一可能是"假"或可能是异常(但是字符串Javadoc似乎排除了后者).
我理解更广泛的观点,非对称性可能equals会导致集合之外的代码出现问题,但我不会在他引用的例子中看到它.
我错过了什么吗?
import java.util.List;
import java.util.ArrayList;
class CIString {
private final String s;
public CIString(String s) {
this.s = s;
}
@Override public boolean equals( Object o ) {
System.out.println("Calling CIString.equals from " + this.s );
if ( o instanceof CIString)
return s.equalsIgnoreCase( ( (CIString) o).s);
if ( o instanceof String)
return s.equalsIgnoreCase( (String) o ); …Run Code Online (Sandbox Code Playgroud) 有效的Java(Joshua Bloch)第17项说:
"设计和文件或继承或禁止它"
然而,只是粗略地浏览Android API就会发现大多数API类都是非最终的; 这是确定的,如果它们也记录为(继承View的Activity,例如).但是也有几个非final类,但是文档没有提到这些类的可继承性.只是一些任意的例子来说明我的观点:
WifiManager,NotificationManager...)UriMatcher.Camera.开放性和可扩展性是Android的哲学,这里的惯例是否反过来?意思是,可以假设所有 Android API类都被设计为继承(无论是明确记录还是其他); 除非宣布最后?
以下是第9项中的示例代码:
public final class PhoneNumber {
private final short areaCode;
private final short prefix;
private final short lineNumber;
@Override
public int hashCode() {
int result = 17;
result = 31 * result + areaCode;
result = 31 * result + prefix;
result = 31 * result + lineNumber;
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
Pg 48指出:"选择值31是因为它是一个奇数素数.如果它是偶数且乘法溢出,信息就会丢失,因为2的muiltiplication相当于移位."
我理解乘2的概念相当于位移.我也知道当我们将一个大数乘以一个大的奇素数时,我们仍会得到溢出(因此信息丢失).我没有得到的是为什么由大奇数素数乘法引起的信息丢失优于由大偶数乘法引起的信息丢失.
从Effective Java中的Exceptions章节:
将代码放在try-catch块中会禁止现有JVM实现可能执行的某些优化
try-catch块为什么以及如何阻止JVM优化?
请看这个链接.关于Enums,布洛赫先生说
Java的枚举类型是通过公共静态最终字段为每个枚举常量导出一个实例的类.
我阅读了Enum类文档,但没有公共静态final字段,那么上述语句如何成立.请解释.谢谢
当我阅读有效Java项目27时,类型之间的投射UnaryFunction<Object>和UnaryFunction<T>困惑我.
interface UnaryFunction<T> {
T apply(T t);
}
public class Main {
private static final UnaryFunction<Object> IDENTITY = new UnaryFunction<Object>() {
public Object apply(Object t) {
return t;
}
};
@SuppressWarnings("unchecked")
public static <T> UnaryFunction<T> identityFunction() {
return (UnaryFunction<T>) IDENTITY;
}
public static void main(String ... args) {
UnaryFunction<A> identityA = Main.identityFunction();
A a = identityA.apply(new A());
}
}
class A {}
Run Code Online (Sandbox Code Playgroud)
为什么UnaryFunction<Object>可以投入UnaryFunction<T>?
我知道通用类型将在编译器之后被删除.因此,(UnaryFunction<T>) IDENTITY最终将(UnaryFunction<Object>) IDENTITY,这将在运行系统中工作. …
可爱的equals和hashcode,所有的理论都在这里,也在这里
我已经决定在我的许多休眠实体/域对象中使用 equals() 和 hashcode() 中自动生成的 id。
但是,许多网站表示您永远不应该这样做,因为在比较或使用哈希码的过程中第一次将对象持久保存到数据库中的风险。
我的观点是,在大多数用例中,这比更改任何其他字段的可能性要小得多。
单个域对象在首次创建时会生成一次 id,而几乎所有其他字段在正常业务流程中都有机会被更改(甚至可以更改唯一的用户名……)。
在我的许多域对象中,唯一 id 几乎是唯一需要考虑的合适字段(人、地址、宠物、...客户等?组合字段是一个好主意,但从不使用自动生成的 id,我认为,不是很好的建议。
我还缺少其他东西吗?
在阅读Joshua Bloch的"Effective Java"之后,这个问题得到了提示.特别是在第10项中,他认为解析对象的字符串表示并将其用于除了友好的打印输出/调试之外的任何事情都是不好的做法.原因是这样的使用"容易出错,导致脆弱的系统在您更改格式时会中断".对我而言,看起来Guava Ordering.usingToString()是一个例子.那么使用它是不好的做法吗?
我正在阅读Joshua Bloch的"Effective Java",在第2项中,他提到了在构造函数中处理几个参数时使用Builder模式的优点.一切都很好,直到我看到传统构造函数和这个模式之间的多个var-args差异.所以,我有一些疑问:
我在代码中没有使用var-args,但是我知道它们的用途.我仍然无法理解上述陈述背后的原因.任何帮助,将不胜感激.
所以我一直在经历"Effective Java 2nd Ed".
在第7项中,他谈到不使用终结器,因为它们可能会导致很多问题.
但是,我们不是使用终结器,而是"提供一种显式终止方法",其中一个例子就是密切语句.我不明白什么是"终止声明,它们和终结者之间有什么区别?
我得出结论,终止一个对象就像归零一样,因此资源被释放.但我想我不太了解它的区别.所以我感谢任何帮助.
谢谢 !