我正在阅读" Effective Java ".
他说,在关于敲定的讨论中
C++析构函数也用于回收其他非内存资源.在Java中,try finally块通常用于此目的.
什么是非内存资源?
数据库连接是非内存资源吗?持有数据库连接的对象是否占用了一些内存?
我读过Joshua Bloch的精彩"有效Java".但书中的一个例子对我来说还不清楚.它来自关于泛型的章节,具体项目是"第28项:使用有界通配符来增加API灵活性".
在这个项目中,它展示了如何使用有界类型参数和有界通配符类型编写从集合中选择最大元素的算法的最通用和防弹(在类型系统的角度)版本.
编写的静态方法的最终签名如下所示:
public static <T extends Comparable<? super T>> T max(List<? extends T> list)
Run Code Online (Sandbox Code Playgroud)
它Collections#max与标准库中的函数大致相同.
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
Run Code Online (Sandbox Code Playgroud)
我理解为什么我们需要在T extends Comparable<? super T>类型约束中使用有界通配符,但它在参数的类型中是否真的有必要?在我看来,这将是相同的,如果我们只留下List<T>或者Collection<T>,是不是?我的意思是这样的:
public static <T extends Comparable<? super T>> T wrongMin(Collection<T> xs)
Run Code Online (Sandbox Code Playgroud)
我写了以下使用两个签名的愚蠢示例,并没有看到任何不同之处:
public class Algorithms {
public static class ColoredPoint extends Point {
public final Color color;
public ColoredPoint(int x, int y, Color color) { …Run Code Online (Sandbox Code Playgroud) 我的问题很理论......这是Class.asSubclass(Javadoc)的签名:
public <U> Class<? extends U> asSubclass(Class<U> clazz)
Run Code Online (Sandbox Code Playgroud)
为什么返回类型中使用了通配符泛型?根据我对泛型的理解,更好的签名可能是:
public <U> Class<U> asSubclass(Class<U> clazz)
Run Code Online (Sandbox Code Playgroud)
因为你可以肯定演员
Class<? extends U>
Run Code Online (Sandbox Code Playgroud)
更简单
Class<U>
Run Code Online (Sandbox Code Playgroud)
Bloch在他的书"Effective Java"中建议(第137页,第28项):
不要将通配符类型用作返回类型.它不会为您的用户提供额外的灵活性,而是迫使他们在客户端代码中使用通配符类型.
这个选择背后的原因是什么?我错过了什么?非常感谢你提前.
编辑: 正如@egelev建议的那样,我确实可以用另一种方式表达我的问题......事实上,"按原样"返回输入参数将毫无意义.所以真正的问题是:与普通的强制转换相比,Class.asSubclass方法的真正用处是什么?如果出现强制转换问题,两者都会抛出ClassCastException.
可能已添加它以避免在特定情况下未经检查的转换:当您将asSubclass方法的结果直接传递给另一个请求约束类型参数的方法时,如此处(取自Effective Java,第146页):
AnnotatedElement element;
...
element.getAnnotation(annotationType.asSubclass(Annotation.class));
Run Code Online (Sandbox Code Playgroud)
上述方法的签名是:
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
Run Code Online (Sandbox Code Playgroud)
在我看来,asSubclass方法只是一种方法来做一个(事实上!)未经检查的强制转换没有正确的编译器警告...
这最终重新提出我以前的问题:签名
public <U> Class<U> asSubclass(Class<U> clazz)
Run Code Online (Sandbox Code Playgroud)
同样有效(即使很奇怪,我也承认)!它将与getAnnotation示例完全兼容,并且不会限制客户端代码强制它使用无意义的通配符泛型.
编辑2: 我认为我的一般问题已经解决了; 非常感谢你.如果有人有关于asSubclass签名正确性的其他好例子,请将它们添加到讨论中,我希望看到一个完整的例子,使用asSubclass和我的签名,显然不起作用.
这来自Effective Java
使用int枚举模式的程序很脆弱.因为int枚举是编译时常量,所以它们被编译到使用它们的客户端中.
有人可以解释为什么int枚举模式被称为编译类型常量以及编译到客户端的含义是什么?
这是一个这样一个常数的例子:
public static final int APPLE_FUJI = 0;
Run Code Online (Sandbox Code Playgroud) 我一直在阅读Joshua Bloch撰写的Effective Java,到目前为止,它确实辜负了它的声誉.第一个项目为构造函数的静态工厂方法提供了令人信服的案例.这么多,我开始质疑好老建设者的有效性:).
本书的优点/缺点总结如下:
好处:
- 他们有名字!
- 我们有全面的实例控制(单身人士,表现等)
- 他们可以返回子类型/接口
- 编译器可以提供类型推断
缺点:
- 私有类不能被子类化
- 它们不像构造函数那样在文档中脱颖而出
第一个缺点实际上可能是A Good Thing(正如书中所提到的).第二个,我认为只是一个小缺点,可以通过即将发布的java版本(javadoc的注释等)轻松解决.
看起来,最终工厂方法几乎具有构造函数的所有优点,许多优点,并没有真正的缺点!
所以,我的问题基本上分为三个部分:
注意:有两个类似的问题:何时使用构造函数以及何时使用getInstance()方法(静态工厂方法)?和对象的创建:构造函数或静态工厂方法.然而,答案要么只是提供上面的列表,要么重申我已经知道的静态工厂方法背后的基本原理.
java constructor design-patterns factory-pattern effective-java
在Joshua Bloch撰写的Effective Java一书中,讨论了一个类如何提供"明智选择的受保护方法"作为其内部工作的钩子.
然后,作者引用了以下文档AbstractList.removeRange():
此方法
clear由此列表及其子列表上的操作调用.重写此方法以利用列表实现的内部可以显着提高clear此列表及其子列表上的操作的性能.
我的问题是,如何覆盖这种方法可以提高性能(而不仅仅是覆盖它)?谁能举个例子?
这是我正在谈论的代码:
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
/**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
private void ensureCapacity() {
if …Run Code Online (Sandbox Code Playgroud) 我的理解是泛型类型是不变的,所以如果我们B作为子类型A,则List<B>与之无关List<A>.因此,铸造将无法正常工作的List<A>和List<B>.
从Effective Java Third Edition我们有这段代码:
// Generic singleton factory pattern
private static UnaryOperator<Object> IDENTIFY_FN = (t) -> t;
@SuppressWarnings("unchecked")
public static <T> UnaryOperator<T> identifyFunction() {
return (UnaryOperator<T>) IDENTIFY_FN; //OK But how, why?
}
public static void main(String[] args) {
String[] strings = {"a", "b", "c"};
UnaryOperator<String> sameString = identifyFunction();
for (String s : strings) {
System.out.println(sameString.apply(s));
}
}
Run Code Online (Sandbox Code Playgroud)
我在这里很困惑.我们已经投下IDENTIFY_FN,其类型UnaryOperator<Object>,对UnaryOperator<T>,它有另一种类型的参数.
当类型擦除发生时String是Object的子类型,但据我所知, …
我意识到已经 充分 讨论了检查异常与Java中未经检查的异常的相对优点,我不打算重新审视整个辩论.
相反,当我阅读Joshua Bloch的Effective Java,第2版时,我想问一个非常具体的问题.在我阅读时,我注意到在第59项("避免不必要地使用已检查的异常")中,Joshua在Java API中给出了一个使用已检查异常的示例.具体来说,在Object:
protected Object clone()
throws CloneNotSupportedException
Run Code Online (Sandbox Code Playgroud)
...然后争辩说它应该是一个未经检查的例外.
如果使用API的程序员不能做得更好,那么未经检查的异常会更合适.未通过此测试的异常的一个示例是CloneNotSupportedException.它由Object.clone引发,只应在实现Cloneable(Item 11)的对象上调用它.实际上,catch块几乎总是具有断言失败的特征.异常的检查性质对程序员没有任何好处,但它需要努力并使程序复杂化.
然后我看着他是否有一个反向的例子,但我找不到一个.
所以我想问一下是否有人可以在Java中提供一个使用未经检查的异常的API示例,但是检查异常是更好的选择,并解释原因.一个现实世界的例子会更可取,但如果能够说明问题的话,我愿意接受一个人为的例子.
编辑: 对于那些投票决定将其视为非建设性的人,我想明确表示我不是在寻找意见,辩论,争论或扩展讨论.我也不参加民意调查.相反,我正在寻找能够清楚地分析收益如何超过成本的例子.(隐含的是承认有成本.)那就是说,我怀疑这个问题的性质是否有可能.我估计Jon Skeet不能这样做,它不可能完成.也许你是对的.如果必须,请关闭.
编辑:虽然我对这个回复不感兴趣,但我只是因为我的接受率而将此奖励给Jon.
Object的clone方法非常棘手.它基于现场副本,而且是"超语言".它创建一个对象而不调用构造函数.无法保证它保留构造函数建立的不变量.多年来,在Sun内外都存在许多错误,这源于这样一个事实,即如果你只是反复调用super.clone直到克隆了一个对象,那么你就拥有了一个浅层的对象副本.
Joshua Bloch用语言外的意思是什么意思?
effective-java ×10
java ×10
generics ×3
api-design ×1
casting ×1
clone ×1
constructor ×1
enums ×1
exception ×1
list ×1
overriding ×1