我一直在阅读Effective Java,我对第一个项目"使用静态工厂方法而不是构造函数"与TDD和依赖注入有关.
该项目表示您应该避免使用public/protected/default构造函数并使用静态工厂公开它.我同意与使用静态工厂相关的所有优点,例如工厂可以有名称,你可以返回子类型,你可以减少冗长等等.但是,我认为缺点是约书亚错过了TDD,因为你的代码中有静态工厂将导致紧密耦合和你不能用它来模拟这个类.我们将无法模拟将拥有静态工厂的类.因此,它阻碍了测试驱动的开发.
第二点,我认为他错过了在今天的企业开发中大多数应用程序使用一个或另一个依赖注入容器.所以,当我们可以使用DI注入依赖项时,为什么要使用它呢?
请解释它如何应用于今天的Java企业开发,包括DI和TDD.
我有以下来自Joshua Bloch的有效Java代码(第9章,第3章,第49页)
如果类是不可变的并且计算哈希代码的成本很高,您可以考虑在对象中缓存哈希代码,而不是每次请求时重新计算它.如果您认为此类型的大多数对象将用作哈希键,则应在创建实例时计算哈希码.否则,您可能会在第一次调用hashCode时选择懒惰地初始化它(Item 71).目前尚不清楚我们的PhoneNumber类是否值得这样做,只是为了向您展示它是如何完成的:
// Lazily initialized, cached hashCode
private volatile int hashCode; // (See Item 71)
@Override public int hashCode() {
int result = hashCode;
if (result == 0) {
result = 17;
result = 31 * result + areaCode;
result = 31 * result + prefix;
result = 31 * result + lineNumber;
hashCode = result;
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是如何缓存(记住hashCode)在这里工作.第一次hashCode()调用方法,没有hashCode将其分配给结果.这个缓存如何工作的简要解释将是伟大的.谢谢
请查看Joshua Bloch的Effective Java 链接.
在第二段中,作者说:
该类是私有的或包私有的,并且您确定它的equals方法永远不会被调用.可以说,在这些情况下应该覆盖该
equals方法,以防它被意外调用:Run Code Online (Sandbox Code Playgroud)@Override public boolean equals(Object o) { throw new AssertionError(); // Method is never called }
请解释一下.我对作者使用术语私有类感到困惑,并且当我们确定不会被调用时,为什么需要重写equals方法.
在Effective Java(第2版)的第2项中,作者提到了以下关于在使用Builders时对参数施加不变量的问题:
在将参数从构建器复制到对象之后检查它们并在对象字段而不是构建器字段(项目39)上检查它们是至关重要的.如果违反了任何不变量,则构建方法应抛出IllegalStateException(Item 60).
这是否意味着在构建方法创建目标对象之后,应将其传递给验证例程以进行任何所需的验证?
另外,有人可以解释一下这背后的原因吗?
我怀疑我遇到过阅读Effective Java.如果它是一个真正简单而直截了当的疑问,我道歉.因此,在第74项 - 明智地实施Serializable中,他说,即使在使用私有和私有领域实施一个好的信息隐藏在你的班级之后,它也很容易失去效力?无论我过去阅读过什么,所有序列化都是将对象转换为字节流形式,反序列化后保留相同的对象.如何在此过程中丢失数据隐藏?
在Effective Java,第1项中,它说静态工厂方法使Collections框架比原本要小得多.有人可以解释一下吗?由于使用静态工厂方法,我无法理解以下是如何实现的?我的意思是我们仍然必须实现那些单独的实现不是吗?
Collections Framework API比它导出32个单独的公共类要小得多,每个方便实现一个.
这是尝试从Effective Java 2nd Edition中仔细理解ITEM 40:设计方法签名的一部分.
建议改进方法签名可读性的一个目的是瞄准四个或更少的参数.建议使用多种技术管理较长的参数列表,其中一种技术如下:
结合前两个方面的第三种技术是使Builder模式(第2项)从对象构造适应方法调用.如果你有一个包含许多参数的方法,特别是如果它们中的一些是可选的,那么定义一个代表所有参数的对象并允许客户端对该对象进行多次"setter"调用是有益的.它设置单个参数或小的相关组.一旦设置了所需的参数,客户端就会调用对象的"执行"方法,该方法对参数进行任何最终有效性检查并执行实际计算.
我熟悉Builder模式,因为它用于对象构造,但我不确定我是否正确理解了如何使其适应方法调用.
这是我到目前为止:(
我试图改进方法的方法调用move)
public class Space {
public static class Builder {
// Required parameters
private final int x;
private final int y;
private final int z;
// optional params
private long time = 0;
public Builder(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Builder time(long val) {
time = val;
return this;
}
public void move() …Run Code Online (Sandbox Code Playgroud) 我正在阅读Effective Java书籍,并为我将来的参考创建笔记,我遇到了Builder Pattern.
好吧,我明白它是什么以及如何使用它.在这个过程中,我创建了两个构建器模式的示例变体.
我需要帮助列出每个人的差异和优势吗?我当然注意到,Example 1暴露较少的方法,通过较少的限制和更通用,允许它更灵活地使用.
请指出我错过的其他事情?
例1
package item2;
/**
* @author Sudhakar Duraiswamy
*
*/
public class Vehicle {
private String type;
private int wheels;
interface Builder<T>{
public T build();
}
public static class CarBuilder implements Builder<Vehicle>{
private String type;
private int wheels;
CarBuilder createVehicle(){
this.type= "Car";
return this;
}
CarBuilder addWheels(int wheels){
this.wheels = wheels;
return this;
}
public Vehicle build(){
Vehicle v = new Vehicle();
v.type = type;
v.wheels = wheels;
return v;
} …Run Code Online (Sandbox Code Playgroud) 在 Effective Java(第 7 章)中,它说
还要注意,我们没有使用 Date 的 clone 方法来制作防御性副本。因为 Date 是非最终的,所以 clone 方法不能保证返回一个类是 java.util.Date 的对象:它可能返回一个专为恶意恶作剧设计的不受信任子类的实例。例如,这样的子类可以在创建时在私有静态列表中记录对每个实例的引用,并允许攻击者访问该列表。这将使攻击者可以自由支配所有实例。为防止此类攻击,请勿使用 clone 方法制作类型可被不受信任方子类化的参数的防御性副本。
我不太明白它的解释。为什么 clone() 不返回 Date 对象?实例怎么可能是不受信任的子类?
我正在学习Effective Java,第8项(在覆盖equals时遵守一般合同).作者已经非常清楚地解释了这一点,但仍有一些部分没有详细阐述.
对于此示例,他将类CaseInsensitiveString定义为:
public final class CaseInsensitiveString {
private final String s;
public CaseInsensitiveString(String s) {
if (s == null)
throw new NullPointerException();
this.s = s;
}
// Broken - violates symmetry!
@Override
public boolean equals(Object o) {
if (o instanceof CaseInsensitiveString)
return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
if (o instanceof String) // One-way interoperability!
return s.equalsIgnoreCase((String) o);
return false;
}
// ... // Remainder omitted
}
Run Code Online (Sandbox Code Playgroud)
在文章的最后,他说:
对于某些类,例如上面的CaseInsensitiveString,字段比较比简单的相等测试更复杂.如果是这种情况,您可能希望存储该字段的规范形式,因此equals方法可以对这些规范形式进行廉价的精确比较,而不是更昂贵的不精确比较.这种技术最适用于不可变类(第15项); 如果对象可以更改,则必须使规范形式保持最新.
我搜索了这个术语,发现它基本上意味着某种东西的标准表示,比如绝对路径,没有任何目录中文件的符号链接.但是我无法理解在这个课程中使用"规范"形式,这在这里会有所帮助.有什么建议?