如何制作包含不可变对象中可变字段的可变对象的防御性副本?
class ImmutableObject {
private final MutableObject immutable_field;
ImmutableObject(MutableObject y) {
this.immutable_field = y;
}
}
class MutableObject {
public int mutable_field;
}
Run Code Online (Sandbox Code Playgroud)
在Effective Java中,Bloch建议在使对象不可变时使所有字段成为最终字段.
有必要这样做吗?不会只给出访问器方法使它不可变.
例如
class A {
private int x;
A (int x) {
this.x = x;
}
}
Run Code Online (Sandbox Code Playgroud)
上述类是不可变的,即使我不申报x的final吗?我错过了什么吗?
这个直接来自Effective java 2.我不确定第2项中的这个陈述是什么意思
Builder模式非常灵活.单个构建器可用于构建多个对象.可以在对象创建之间调整构建器的参数以改变对象.
我无法想出一个例子来做到这一点.请举例说明一下.
这是Joshua Bloch撰写的有效Java第2版第2章第24页的代码.在他定义的pop方法中,他使用了elements[--size].我想知道他为什么使用--size,而elements[size--]应该返回相同的正确?
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 …Run Code Online (Sandbox Code Playgroud) 对于具有数组字段的类,Josh说如果clone方法只返回super.clone(),则生成的类实例将在原始字段中具有正确的值,但其数组字段将引用与原始类实例相同的数组.修改原始内容会破坏不变量,反之亦然.
他使用了自定义Stack实现的例子,我使用的是一个简单的Student类
class Student implements Cloneable {
private String name;
private int age;
private int[] marks = {90, 70, 80};
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setMarks(int[] marks) {
this.marks = marks;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
@Override
public String toString() {
return "Student - Name …Run Code Online (Sandbox Code Playgroud) 使用下面的例子,Joshua Bloch的防御性复制技术是否有优雅的Java实现?nullChecking确实是我认为的问题,但也许有一种更简单的方法来实现防御性复制.
public class Audit {
private Date dateCompleted;
...
public Audit() {
super();
}
//defensive copy of dateCompleted
public final Date getDateCompleted() {
if (dateCompleted != null){
return new Date(dateCompleted.getTime());
}else{
return null;
}
}
public final void setDateCompleted(Date dateCompleted) {
if (dateCompleted != null){
this.dateCompleted = new Date(dateCompleted.getTime());
}else{
this.dateCompleted = null;
}
}
...
}
Run Code Online (Sandbox Code Playgroud) 我现在正在阅读Joshua Bloch的"Effective Java",当我读到第41项"明智地使用重载"时,我很困惑,因为那里使用的例子.我在计算机上试过它,它确实在书中做了它.但我不明白为什么!
这是这个例子:
public class SetList {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<Integer>();
List<Integer> list = new ArrayList<Integer>();
for (int i = -3; i < 3; i++) {
set.add(i);
list.add(i);
}
for (int i = 0; i < 3; i++) {
set.remove(i);
list.remove(i);
}
System.out.println(set + " " + list);
}
}
Run Code Online (Sandbox Code Playgroud)
它输出:
[-3, -2, -1] [-2, 0, 2]
我知道这个例子中的list.remove()应该通过索引删除,但它不会!在列表填充值后,它是:[ - 3,-2,-1,0,1,2].因此,当我们删除0,1和2个元素时,我们应该使用[0,1,2],而不是[-2,0,2].那里发生了什么?
在《Effective Java -> Item 66》中,Joshua 强调需要同步读取和写入操作以避免活性失败。
在这个特定的示例中,我认为写入方法的同步是多余的。即使删除同步写入方法后,程序运行和终止也不会出现任何问题。需要同步来查看对象的一致状态,这是通过同步读取方法来实现的。
请让我知道您对此的看法。
import java.util.concurrent.TimeUnit;
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (!isStopRequested())
i++;
}
}).start();
;
TimeUnit.SECONDS.sleep(1);
setStopRequested(true);
}
private static synchronized boolean isStopRequested() {
return stopRequested;
}
private static void setStopRequested(boolean stopRequested) {
StopThread.stopRequested = stopRequested;
}
}
Run Code Online (Sandbox Code Playgroud) Effective Java,第43项规定:
返回不可修改的空集合而不是
null.
到现在为止还挺好.有什么指导方针,到底要返回什么?这个问题甚至有意义吗?我在想的是:
LinkedList<>或是否有所不同ArrayList<>(0)?HashMap<>或者是否有所不同TreeMap<>?性能差异?几乎不.
内存占用?也许.
CPU占用空间?也许.
是否应该全局声明这些静态返回(即缓存)?
以下代码来自Effective Java book:
Set<Integer> integers = ... ;
Set<Double> doubles = ... ;
Set<Number> numbers = union(integers, doubles);
Run Code Online (Sandbox Code Playgroud)
这段代码没有编译,作者建议通过告诉编译器确切的类型来解决这个问题,如下所示:
Set<Number> numbers = Union.<Number>union(integers, doubles)
Run Code Online (Sandbox Code Playgroud)
如果联合的签名如下,为什么早期的程序不能编译?这个特定的解决方法成语是什么?
public static <E> Set<E> union(Set<? extends E> s1,
Set<? extends E> s2)
Run Code Online (Sandbox Code Playgroud) effective-java ×10
java ×10
cloning ×1
collections ×1
generics ×1
immutability ×1
javabeans ×1
stack ×1